zoukankan      html  css  js  c++  java
  • 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];
            }
    	}
    };
    

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

  • 相关阅读:
    四,awk格式化
    printf命令详解
    三,awk变量
    二,awk分隔符
    一,AWK基础
    【leetcode_easy_array】1399. Count Largest Group
    【leetcode_easy_array】1184. Distance Between Bus Stops
    【leetcode_easy_array】1346. Check If N and Its Double Exist
    【leetcode_easy_array】1304. Find N Unique Integers Sum up to Zero
    【leetcode_easy_array】1337. The K Weakest Rows in a Matrix
  • 原文地址:https://www.cnblogs.com/Heizesi/p/11613688.html
Copyright © 2011-2022 走看看