力扣-第291场周赛

第1题

6047. 移除指定数字得到的最大结果

给你一个表示某个正整数的字符串 number 和一个字符 digit 。
从 number 中 恰好 移除 一个 等于 digit 的字符后,找出并返回按 十进制 表示 最大 的结果字符串。生成的测试用例满足 digit 在 number 中出现至少一次。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-digit-from-number-to-maximize-result

示例 1:
输入:number = "123", digit = "3"
输出:"12"
解释:"123" 中只有一个 '3' ,在移除 '3' 之后,结果为 "12" 。

示例 2:
输入:number = "1231", digit = "1"
输出:"231"
解释:可以移除第一个 '1' 得到 "231" 或者移除第二个 '1' 得到 "123" 。
由于 231 > 123 ,返回 "231" 。

示例 3:
输入:number = "551", digit = "5"
输出:"51"
解释:可以从 "551" 中移除第一个或者第二个 '5' 。
两种方案的结果都是 "51" 。

提示:
2 <= number.length <= 100
number 由数字 '1' 到 '9' 组成
digit 是 '1' 到 '9' 中的一个数字
digit 在 number 中出现至少一次

题解

遍历字符串的每个字符,把 digit 前后的字符串连接起来,构成新的字符串,放到 list中,再通过Collections 对 list 进行排序,取出最大值即可。

点击查看代码

c++

class Solution {
public:
    string removeDigit(string number, char digit) {
        vector<string> v;
        for(int i=0, len=number.length(); i<len; i++){
            if(number[i] == digit){
                v.push_back(number.substr(0,i) + number.substr(i+1,len));
            }
        }

        string maxv = v[0];
        for(int i=1; i<v.size(); i++){
            if(compareAB(maxv, v[i])==-1) maxv = v[i]; 
        }

        return maxv;
    }
    // 比较字符串数字a,b大小,a>b返回1,a=b返回0,a<b返回-1;
    int compareAB(string a, string b){
        if(a.length()>b.length()) return 1;
        else if(a.length()<b.length()) return -1;
        for(int i=0; i<a.length(); i++){
            if(a[i]>b[i]) return 1;
            else if(a[i]<b[i]) return -1;
        }

        return 0;
    }
};

java:

class Solution {
    public String removeDigit(String number, char digit) {
        int n = number.length();
        List<String> list = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            if (number.charAt(i) == digit) {
                String s = number.substring(0, i) + number.substring(i + 1, n);
                list.add(s);
            }
        }
        Collections.sort(list);
        return list.get(list.size() - 1);
    }
}

看到一个比较妙的方法

class Solution {
public:
    string removeDigit(string number, char digit) {
        int pre = -1;
        for (int i = 0; i < number.length(); i += 1) {
            if (number[i] == digit) {
                pre = i;
                if (i + 1 < number.length() && number[i + 1] > number[i])   // 只需要比较下一位就可,而非字串
                    break;
            }
        }
        return number.substr(0, pre) + number.substr(pre + 1);
    }
};

第2题

6048. 必须拿起的最小连续卡牌数

给你一个整数数组 cards ,其中 cards[i] 表示第 i 张卡牌的 值 。如果两张卡牌的值相同,则认为这一对卡牌 匹配 。
返回你必须拿起的最小连续卡牌数,以使在拿起的卡牌中有一对匹配的卡牌。如果无法得到一对匹配的卡牌,返回 -1

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-consecutive-cards-to-pick-up

示例 1:
输入:cards = [3,4,2,3,4,7]
输出:4
解释:拿起卡牌 [3,4,2,3] 将会包含一对值为 3 的匹配卡牌。注意,拿起 [4,2,3,4] 也是最优方案。

示例 2:
输入:cards = [1,0,5,3]
输出:-1
解释:无法找出含一对匹配卡牌的一组连续卡牌。

提示:
1 <= cards.length <= 1e5
0 <= cards[i] <= 1e6

题解

题目意思实际上就是求数组中任意2个重复元素的最短距离,没有重复就返回-1;

解题思路:

  1. 遍历数组cards,使用map存储数组的每个元素,key为元素的值 cards[i],value为元素的下标 i;
  2. 当map中已经存在对应的key时(即遇到重复元素时),计算当前遍历到的元素的下标与前一个相同元素的下标的差dist
  3. 判断当前差值与之前的差值ans哪个小,并更新 ans 变量为最小的差值
  4. 更新map中对应key为当前遍历的元素的下标
class Solution {
    public int minimumCardPickup(int[] cards) {
        int ans = Integer.MAX_VALUE;
        HashMap<Integer,Integer> m = new HashMap<>();
        for (int i = 0; i < cards.length; i++) {
            if(!m.containsKey(cards[i])){
                m.put(cards[i], i);
            } else {
                int dist = i - m.get(cards[i]) + 1;
                ans = Math.min(dist, ans);
                m.put(cards[i], i);
            }
        }
        return ans==Integer.MAX_VALUE?-1:ans;
    }
}

第4题

6050. 字符串的总引力

字符串的 引力 定义为:字符串中不同字符的数量。

例如,"abbca" 的引力为 3 ,因为其中有 3 个不同字符 'a'、'b' 和 'c' 。
给你一个字符串 s ,返回 其所有子字符串的总引力 。

子字符串定义为:字符串中的一个连续字符序列。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/total-appeal-of-a-string

示例 1:

输入:s = "abbca"
输出:28
解释:"abbca" 的子字符串有:

  • 长度为 1 的子字符串:"a"、"b"、"b"、"c"、"a" 的引力分别为 1、1、1、1、1,总和为 5 。
  • 长度为 2 的子字符串:"ab"、"bb"、"bc"、"ca" 的引力分别为 2、1、2、2 ,总和为 7 。
  • 长度为 3 的子字符串:"abb"、"bbc"、"bca" 的引力分别为 2、2、3 ,总和为 7 。
  • 长度为 4 的子字符串:"abbc"、"bbca" 的引力分别为 3、3 ,总和为 6 。
  • 长度为 5 的子字符串:"abbca" 的引力为 3 ,总和为 3 。
    引力总和为 5 + 7 + 7 + 6 + 3 = 28 。

提示:
1 <= s.length <= 1e5
s 由小写英文字母组成

题解

题解源自作者:endlesscheng
链接:https://leetcode-cn.com/problems/total-appeal-of-a-string/solution/by-endlesscheng-g405/

思路:从左往右遍历 s,将 s[i] 添加到以 s[i-1] 结尾的子串的末尾后,引力值增加多少?

分类讨论:

  • 如果 s[i] 之前没有遇到过,那么每个子串的引力值都会增加 1,引力值之和会增加 i,再加上 1,即 s[i] 单独组成的子串的引力值。
  • 如果 s[i] 之前遇到过,设其上次出现的下标为 j,那么向子串 s[0...i-1], s[1...i-1], s[2...i-1],...,s[j...i-1] 的末尾添加 s[i]后,引力值是不会变化的,因为 s[i] 已经在 s[j] 处出现过了;而子串 s[j+1...i-1], s[j+2...i-1], ..., s[i-1...i-1] 由于不包含字符 s[i],这些子串的引力值都会增加 1,因此有 i-j-1 个子串的引力值会增加 1,引力值之和会增加 i-j-1,再加上 1,即 s[i] 单独组成的子串的引力值。

模拟上述过程,遍历 s 的过程中用一个变量 sumG 维护以 s[i] 结尾的子串的引力值之和,同时用一个数组 pos 记录每个字符最近一次出现的下标。

累加遍历中的 sumG 即为答案。

    public long appealSum(String s) {
        long ans = 0L, sumG = 0L;
        int[] pos = new int[26];
        Arrays.fill(pos, -1);

        for (int i = 0; i < s.length(); i++) {
            int c = (s.charAt(i) - 'a');   // 把s中的一个字符映射成一个0~25的数字
            sumG += i - pos[c]; // pos中值在未被修改之前都是-1,只有遇到重复字符时才会用对应字符的下标(下面第2行代码)覆盖掉-1
            ans += sumG;
            pos[c] = i;
        }
        return ans;
    }
posted @ 2022-05-01 14:11  aJream  阅读(58)  评论(0编辑  收藏  举报