Leetcode刷题 2021.01.31

Leetcode839 相似字符串组

如果交换字符串 X 中的两个不同位置的字母,使得它和字符串 Y 相等,那么称 X 和 Y 两个字符串相似。如果这两个字符串本身是相等的,那它们也是相似的。

例如,“tars” 和 “rats” 是相似的 (交换 0 与 2 的位置); “rats” 和 “arts” 也是相似的,但是 “star” 不与 “tars”,“rats”,或 “arts” 相似。

总之,它们通过相似性形成了两个关联组:{“tars”, “rats”, “arts”} 和 {“star”}。注意,“tars” 和 “arts” 是在同一组中,即使它们并不相似。形式上,对每个组而言,要确定一个单词在组中,只需要这个词和该组中至少一个单词相似。

给你一个字符串列表 strs。列表中的每个字符串都是 strs 中其它所有字符串的一个字母异位词。请问 strs 中有多少个相似字符串组?

没有看题解就做出来的每日一题的困难题,其实也没有那么难。就是并查集加判断字符串而已,最后返回连通分量的数目。一开始觉得判断字符串那里可能会超时,没想到直接就过了。

class Solution {
    public int numSimilarGroups(String[] strs) {
        int n = strs.length;
        UnionFind uf = new UnionFind(n);
        for(int i = 0; i < n; i++){
            for(int j = i + 1; j < n; j++){
                if (helper(strs[i], strs[j])){
                    uf.union(i, j);
                }
            }
        }

        return uf.size;
    }
	
	//判断两个字符串是否交换一次就能相似
    private boolean helper(String s1, String s2){
        char[] arr1 = s1.toCharArray();
        char[] arr2 = s2.toCharArray();
        char c1 = 'A', c2 = 'B', k = 1;
        for(int i = 0; i < arr1.length; i++){
            if (arr1[i] == arr2[i]){
                continue;
            }else{
                if (--k < 0) return false;
                if (c1 == 'A'){
                    c1 = arr2[i];
                    c2 = arr1[i];
                }else{
                    if (arr1[i] != c1 || arr2[i] != c2) return false;
                }
            }
        }
        return true;
    }
	
	//并查集
    class UnionFind{
        int[] parent;
        int size;

        public UnionFind(int n){
            this.size = n;
            parent = new int[n];
            for(int i = 0; i < n; i++){
                parent[i] = i;
            }
        }

        public int find(int i){
            if (parent[i] == i) return i;
            return parent[i] = find(parent[i]);
        }

        public void union(int i, int j){
            int root1 = find(i);
            int root2 = find(j);
            if (root1 == root2) return;
            parent[root1] = root2;
            size--;
        }


    }
}

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

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

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

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

本题答案保证唯一。

看到这种类似于消消乐的题目,首先就是想到用栈进行模拟了。遇到三个字符就消除,但是这里可能会有两个字符中间隔着其他字符,再遇到一个字符,所以还需要一个变量记录目前相等的字符的个数。所以另外再用一个类记录。

class Solution {
    public String removeDuplicates(String s, int k) {
        char[] arr = s.toCharArray();
        Deque<Ele> stack = new ArrayDeque<>();
        for(int i = 0; i < arr.length; i++){
         	//如果栈为空,或者栈顶元素不相同,就放进1
            if (stack.isEmpty() || stack.peek().c != arr[i]) {
                stack.push(new Ele(arr[i], 1));
            }else{
            	//相同的话,就在原来的基础上加1
                stack.push(new Ele(arr[i], stack.peek().num + 1));
                //相同数目到k个就全都pop出去
                if (stack.peek().num == k){
                    for(int j = 0; j < k; j++) stack.pop();
                }
            }
        }
        //用StringBuilder返回
        StringBuilder sb = new StringBuilder();
        for(Ele ele : stack){
            sb.append(ele.c);
        }
        return sb.reverse().toString();
    }
	
	//新的类,保存字符和连续相等的字符数目
    class Ele{
        char c;
        int num;
        public Ele(char c, int num){
            this.c = c;
            this.num = num;
        }
    }
}

Leetcode1208 尽可能使字符串相等

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

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

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

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

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

这道题还是容易想到的,基本的滑动窗口而已,好像没什么可说的。作为基本题,应该熟练掌握。

class Solution {
    public int equalSubstring(String s, String t, int maxCost) {
        char[] arr1 = s.toCharArray();
        char[] arr2 = t.toCharArray();

        int res = 0, i = 0, j = 0, n = arr1.length, sum = 0;
        //滑动窗口过程中更新全局最大值
        while (j < n){
            sum += Math.abs(arr1[j] - arr2[j]);
            j++;
            while (sum > maxCost){
                sum -= Math.abs(arr1[i] - arr2[i]);
                i++;
            }
            res = Math.max(res, j - i);
        }

        return res;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值