• LeetCode Weekly 156


    LeetCode Weekly 156

    5205.独一无二的出现次数

    给你一个整数数组 arr,请你帮忙统计数组中每个数的出现次数。

    如果每个数的出现次数都是独一无二的,就返回 true;否则返回 false。

    示例 1:

    输入:arr = [1,2,2,1,1,3]
    输出:true
    解释:在该数组中,1 出现了 3 次,2 出现了 2 次,3 只出现了 1 次。没有两个数的出现次数相同。

    示例 2:

    输入:arr = [1,2]
    输出:false

    示例 3:

    输入:arr = [-3,0,1,-3,1,1,1,-3,10,0]
    输出:true

    提示:

    1 <= arr.length <= 1000
    -1000 <= arr[i] <= 100

    很简单的问题而且数据范围也很小,直接用数组记出现的数字然后再判重

    int num[2001];
    bool vised[2001];
    class Solution {
    public:
        bool uniqueOccurrences(vector<int>& arr)
        {
            memset(num,0,sizeof(num));
            memset(vised,0,sizeod(vised));
            int len=arr.size();
            for(int i=0;i<len;i++)
            {
                int tmp=arr[i];
                if(tmp<0)
                {
                    tmp*=-1;
                    tmp+=1000;
                }//将数字简单映射一下
                num[tmp]++;
                vised[tmp]=1;
            }
            for(int i=0;i<=2000;i++)
            {
                if(vised[i])
                {
                    for(int j=0;j<=2000;j++)
                    {
                        if(i!=j)
                        {
                            if(num[i]==num[j])
                            {
                                return false;
                            }
                        }
                    }
                }
            }
            return true;
        }
    };
    

    5207. 尽可能使字符串相等

    给你两个长度相同的字符串,s 和 t。

    将 s 中的第 i 个字符变到 t 中的第 i 个字符需要 |s[i] - t[i]| 的开销(开销可能为 0),也就是两个字符的 ASCII 码值的差的绝对值。

    用于变更字符串的最大预算是 maxCost。在转化字符串时,总开销应当小于等于该预算,这也意味着字符串的转化可能是不完全的。

    如果你可以将 s 的子字符串转化为它在 t 中对应的子字符串,则返回可以转化的最大长度。

    如果 s 中没有子字符串可以转化成 t 中对应的子字符串,则返回 0。

    示例 1:

    输入:s = "abcd", t = "bcdf", cost = 3
    输出:3
    解释:s 中的 "abc" 可以变为 "bcd"。开销为 3,所以最大长度为 3。

    遇到这种区间费用问题一般用前缀数组可以使操作更加简单,记cost(i)为前i个字符的开销,这样cost(j+1)-cost(i)就是j到i这一区间的开销。同时用一个指针指向最大段的开端,每当费用超过时就将指针前移直到小于等于maxCost
    再不断更新更大的答案就行了,最坏时间复杂度为O(n^2),但数据似乎没有这么毒瘤。。。更正:是O(n)哒!

    long long cost[100001];
    class Solution {
    public:
        int equalSubstring(string s, string t, int maxCost)
        {
            memset(cost,0,sizeof(cost));
            int len=s.size();
            int maxlen=0;
            int pl=1;
            for(int i=0;i<len;i++)
            {
                cost[i+1]=abs(s[i]-t[i])+cost[i];
                if(cost[i+1]-cost[pl]<=maxCost)
                {
                    maxlen=max(maxlen,i-pl+2);
                }
                else
                {
                    while(cost[i+1]-cost[pl]>maxCost && pl<=i+1)
                    {
                        pl++;
                    }
                }
            }
            return maxlen;
        }
    };
    

    5206.删除字符串中的所有相邻重复项 II

    给你一个字符串 s,「k 倍重复项删除操作」将会从 s 中选择 k 个相邻且相等的字母,并删除它们,使被删去的字符串的左侧和右侧连在一起。

    你需要对 s 重复进行无限次这样的删除操作,直到无法继续为止。

    在执行完所有删除操作后,返回最终得到的字符串。

    本题答案保证唯一。

    示例 1:

    输入:s = "abcd", k = 2
    输出:"abcd"
    解释:没有要删除的内容。

    示例 2:

    输入:s = "deeedbbcccbdaa", k = 3
    输出:"aa"
    解释:
    先删除 "eee" 和 "ccc",得到 "ddbbbdaa"
    再删除 "bbb",得到 "dddaa"
    最后删除 "ddd",得到 "aa"

    直接上栈,相当于在线的模拟每个字符入栈的操作,同时记录下相同字母的数量。每次进栈前检查一下是否达到k,是的话就将栈顶前k个弹出。虽然不难想但是有点难写。

    stack<pair<char,int> > sta;
    char tmp[100001];
    class Solution {
    public:
        string removeDuplicates(string s, int k)
        {
            for(auto i:s)//依次枚举s中的字符
            {
                if(sta.empty())
                {
                    sta.push(make_pair(i,1));
                }
                else
                {
                    pair<char,int> now=sta.top();
                    if(now.first==i)
                    {
                        sta.push(make_pair(i,sta.top().second+1));//相同则次数+1
                    }
                    else
                    {
                        sta.push(make_pair(i,1));
                    }
                }
                while(!sta.empty() && sta.top().second==k)//检查是否达到k次
                {
                    for(int j=0;j<k;j++)
                    {
                        sta.pop();
                    }
                }
            }
            int num=sta.size();
            tmp[num]=0;
            for(int i=num-1;i>=0;i--)
            {
                tmp[i]=sta.top().first;
                sta.pop();
            }
            string ans(tmp);
            return ans;
        }
    };
    
    

    5208.穿过迷宫的最少移动次数

    你还记得那条风靡全球的贪吃蛇吗?

    我们在一个 n*n 的网格上构建了新的迷宫地图,蛇的长度为 2,也就是说它会占去两个单元格。蛇会从左上角((0, 0) 和 (0, 1))开始移动。我们用 0 表示空单元格,用 1 表示障碍物。蛇需要移动到迷宫的右下角((n-1, n-2) 和 (n-1, n-1))。

    每次移动,蛇可以这样走:

    如果没有障碍,则向右移动一个单元格。并仍然保持身体的水平/竖直状态。
    如果没有障碍,则向下移动一个单元格。并仍然保持身体的水平/竖直状态。
    如果它处于水平状态并且其下面的两个单元都是空的,就顺时针旋转 90 度。蛇从((r, c)、(r, c+1))移动到 ((r, c)、(r+1, c))。
    如果它处于竖直状态并且其右面的两个单元都是空的,就逆时针旋转 90 度。蛇从((r, c)、(r+1, c))移动到((r, c)、(r, c+1))。

    返回蛇抵达目的地所需的最少移动次数。

    如果无法到达目的地,请返回 -1。

    示例 1:

    输入:grid = [[0,0,0,0,0,1],
    [1,1,0,0,1,0],
    [0,0,0,0,1,1],
    [0,0,1,0,1,0],
    [0,1,1,0,0,0],
    [0,1,1,0,0,0]]
    输出:11
    解释:
    一种可能的解决方案是 [右, 右, 顺时针旋转, 右, 下, 下, 下, 下, 逆时针旋转, 右, 下]。

    方格上的最短路,不是bfs就是dp,但这道题的状态转移很多用bfs的话码量惊人(dp的也不少)。

    考虑用动态规划做,用dp(i,j,k)来表示从起点到蛇尾位于(i,j)蛇身状态为k(0表示蛇身水平,1表示蛇身竖直)时的最小移动次数。虽然题面关于走法写的很清楚,但正常人也不会想到这个蛇能平移。。。

    同时因为蛇是向左下移动,因此从左向下枚举。同时蛇的转动需要2X2的方格,所以2X2的情况和非2X2的情况需要分别转移。

    int dp[101][101][2];
    class Solution {
    public:
    	int minimumMoves(vector<vector<int>>& grid)
        {
    		int n=grid.size();
    		memset(dp,0x3f,sizeof(dp)); 
    		dp[0][0][0]=0;//初始化除0,0,0的状态其它都是无限大(非法)
    		for(int i=0;i<n;i++)
            {
    			for(int j=0;j<n;j++)
                {
    				if(!grid[i][j])
                    {
    					if(i+1<n && j+1<n && !grid[i+1][j] && !grid[i][j+1] && !grid[i+1][j+1])//先考虑2X2的情况
                        {
    						dp[i][j][0]=min(dp[i][j][0],dp[i][j][1]+1);
    						dp[i][j][1]=min(dp[i][j][1],dp[i][j][0]+1);
    						dp[i+1][j][0]=min(dp[i+1][j][0],dp[i][j][0]+1);
    						dp[i][j+1][1]=min(dp[i][j+1][1],dp[i][j][1]+1);
    					}
                        if(j+2<n && !grid[i][j+1] && !grid[i][j+2])
                        {
                            dp[i][j+1][0]=min(dp[i][j+1][0],dp[i][j][0]+1);
                        }
    					if(i+2<n && !grid[i+1][j] && !grid[i+2][j])
                        {
                            dp[i+1][j][1]=min(dp[i+1][j][1],dp[i][j][1]+1);
                        }
    				}
    			}
    		}
            if(dp[n-1][n-2][0]==0x3f3f3f3f)//如果结果无限大则表示没法到达
            {
                return -1;
            }
    		else
            {
                return dp[n-1][n-2][0];
            }
    	}
    };
    

    这场比赛的题目都是说难不难,但就是不好直接想出来的类型,这样的题目很有价值。

  • 相关阅读:
    109 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 03 新增功能及实现 05 问题解析--通过一个方法完成学生和专业的双向关联
    108 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 03 新增功能及实现 04 问题解析--数组未实例化造成的空指针异常
    107 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 03 新增功能及实现 03 编写方法完成学生个数统计功能
    106 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 03 新增功能及实现 02 新增属性完成学生信息存储
    105 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 03 新增功能及实现 01 新增需求及分析
    session与cookie的区别和联系
    session和cookie的区别
    Web服务器主动推送技术
    webSocket的场景应用
    TCP、Http和Socket 优劣比较
  • 原文地址:https://www.cnblogs.com/Heizesi/p/11613688.html
Copyright © 2020-2023  润新知