Leetcode 周赛题解 215

今天的leetcode最后一题是动态规划,比较难,适合对DP比较熟练的童鞋去完成,讲起来也比较费劲,这里就只讲下第二道和第三道题,第一道水题略过。

5603. 确定两个字符串是否接近

题目内容:

如果可以使用以下操作从一个字符串得到另一个字符串,则认为两个字符串 接近 :

操作 1:交换任意两个 现有 字符。

例如,abcde -> aecdb

操作 2:将一个 现有 字符的每次出现转换为另一个 现有 字符,并对另一个字符执行相同的操作。

例如,aacabb -> bbcbaa(所有 a 转化为 b ,而所有的 b 转换为 a )

你可以根据需要对任意一个字符串多次使用这两种操作。

给你两个字符串,word1 和 word2 。如果 word1 和 word2 接近 ,就返回 true ;否则,返回 false 。

解题思路:

刚开始看题目差点用DP的思路去解题,仔细思考后发现这道题是有规律的。

这道题输入2个字符串a和b,看是否能从a通过操作1、2转换为b。

对于操作1,任意交换2个现有字符,不管怎样交换,字符串里面的字符不会变化,也就是说,a和b的长度肯定是一样的,并且拥有的字符集也一样。

对于操作2,可以转换任意2个类型的字符,那么这里转换后,每个字符的数量按大小排序后是不变的,只要保证2个字符串中字符数量一致,那么就可以转换。

代码如下:

class Solution {
     
public:
    bool closeStrings(string word1, string word2) {
     
        if(word1.length() != word2.length()){
     
            return false;
        }

        std::vector<int> w1(26);
        std::vector<int> w2(26);
        for(auto v:word1){
     
            w1[v-'a']++;
        }
        for(auto v:word2){
     
            w2[v-'a']++;
            // 相同字符
            if(w1[v-'a'] == 0){
     
                return false;
            }
        }

        // 数量相同
        std::sort(w1.begin(), w1.end());
        std::sort(w2.begin(), w2.end());

        for(auto i=0; i<26; i++){
     
            if(w1[i] != w2[i]){
     
                return false;
            }
        }
        return true;
    }
};

5602. 将 x 减到 0 的最小操作数

题目内容:

给你一个整数数组 nums 和一个整数 x 。每一次操作时,你应当移除数组 nums 最左边或最右边的元素,然后从 x 中减去该元素的值。请注意,需要 修改 数组以供接下来的操作使用。

如果可以将 x 恰好 减到 0 ,返回 最小操作数 ;否则,返回 -1 。

解题思路:

这个题目如果直接做,需要处理两端的数据,处理起来很难受,一开始就是这种思路的,用搜索的方法解题,这道题和leetcode经典的子数组求和很像,然而这次是反着来的。

题目意思是从左边或者右边减去一个元素,使得剪掉的总值恰好是x。

反着理解其实就是:数组nums的子数组中,和为sum(nums)-x的子数组是否存在。

于是题目变得比较简单,子数组求和就是前缀和处理。

class Solution {
     
public:
    int minOperations(vector<int>& nums, int x) {
     
        int left = 0;
        int right = left +1;
        int target = 0;
        for(int i=0; i<nums.size();i++){
     
            target += nums[i];
        }
        int res = -1;
        target -= x;
        if(target ==0){
     
            return nums.size();
        }

        int temp = nums[left] + nums[right];
        while(left<=right && right <nums.size()){
     
            if(temp == target){
     
                res = max(right-left+1, res);
            }
            if(temp <= target){
     
                right ++;
                temp += nums[right];
            }else if(temp >target){
     
                left ++;
                temp -= nums[left-1];
            }
        }
        if(res == -1)
            return res;
        return nums.size() - res;
    }
};

做题总结:

通过上面的2题目,可以发现都是将原有的题意做了一次转换,在转换后的思路上曲线解题,这样解题思路会很简单,并且效率也高,代码可读性也会好一些。

好了,这就是这周的算法题解,小编算法水平有限,第四题看了下没做出来,题解理解起来也比较花时间,就不在这篇文章里详细说明了。下周继续~

个人公众号:ACM算法日常

专注于基础算法的研究工作,深入解析ACM算法题,五分钟阅读,轻松理解每一行源代码。内容涉及算法、C/C++、软件设计等。

image

你可能感兴趣的:(ACM算法,C/C++,leetcode)