Leetcode刷题 2021.01.25

Leetcode481 神奇字符串

神奇的字符串 S 只包含 ‘1’ 和 ‘2’,并遵守以下规则:

字符串 S 是神奇的,因为串联字符 ‘1’ 和 ‘2’ 的连续出现次数会生成字符串 S 本身。

字符串 S 的前几个元素如下:S = “1221121221221121122 …”

如果我们将 S 中连续的 1 和 2 进行分组,它将变成:

1 22 11 2 1 22 1 22 11 2 11 22 …

并且每个组中 ‘1’ 或 ‘2’ 的出现次数分别是:

1 2 2 1 1 2 1 2 2 1 2 2 …

你可以看到上面的出现次数就是 S 本身。

给定一个整数 N 作为输入,返回神奇字符串 S 中前 N 个数字中的 ‘1’ 的数目。

注意:N 不会超过 100,000。

没什么特别的技巧,就是模拟这个写法而已。注意一开始先设定前三个数,因为后面的数会越来越多,不会造成不知道后面是什么数的情况乱。这句话可能读不懂,但是明白题目意思的读者应该能理解


class Solution {
    public int magicalString(int n) {
        if (n == 0) return 0;
        if (n <= 3) return 1;
        //设置一个数组,设定数组的前三个数
        int[] arr = new int[n];
        arr[0] = 1;
        arr[1] = 2;
        arr[2] = 2;
        int i = 2, j = 3, res = 1;
        int level = 1;
        while (j < n){
            int count = arr[i];
            //双指针模拟,如果为1就res++
            for(int k = 0; k < count; k++){
                if (j + k >= n) break;
                if (level % 2 == 0){
                    arr[j + k] = 2;
                }else{
                    arr[j + k] = 1;
                    res++;
                }
            }
            level++;
            j = j + count;
            i++;
        }

        return res;
    }
}

Leetcode443 压缩字符串

给定一组字符,使用原地算法将其压缩。

压缩后的长度必须始终小于或等于原数组长度。

数组的每个元素应该是长度为1 的字符(不是 int 整数类型)。

在完成原地修改输入数组后,返回数组的新长度。

这类双指针题其实本质都不难,关键是一些边界的地方,有时候会整不明白,应该多调试几遍就差不多了。思路还是比较清晰的,因为要原地修改,就双指针获取压缩字符的长度。再根据一些条件进行判断就行了。

class Solution {
    public int compress(char[] chars) {
        int i = 0, j = 0, n = chars.length, res = 0, index = 0;
        //双指针常规写法
        while (j < n){
            while (j < n && chars[j] == chars[i]){
                j++;
            }
            //获取字符的长度
            int count = j - i;
            //把第一个改成该字符
            chars[index] = chars[i];
            //获取长度的位数
            int len = getNumLength(count);
            //为1的话就不需要后面加数字了
            if (count != 1){
            	//根据位数填入相应的数字
                for(int k = index + len; k > index; k--){
                    if (count == 0) break;
                    chars[k] = (char) (count % 10 + '0');
                    count /= 10;
                }
                index += len + 1;
            }else{
                index++;
            }
            //更新i
            i = j;
        }

        return index;
    }

    private int getNumLength(int x){
        int res = 0;
        while (x != 0){
            res++;
            x /= 10;
        }
        return res;
    }
}

Leetcode959 由斜杠划分区域

在由 1 x 1 方格组成的 N x N 网格 grid 中,每个 1 x 1 方块由 /、\ 或空格构成。这些字符会将方块划分为一些共边的区域。

(请注意,反斜杠字符是转义的,因此 \ 用 “\” 表示。)。

返回区域的数目。

今天的每日一题,又是并查集。虽然是并查集但是却毫无头绪,并查集难的地方就在于不知道怎么去合并,感觉有各种的奇淫巧计。这道题的话也是如此,参考了官方代码。



class Solution {
    public int regionsBySlashes(String[] grid) {
        int n = grid.length;
        //每一个小格都分成四个小小格
        int size = 4 * n * n;
        UnionFind uf = new UnionFind(size);

        for(int i = 0; i < n; i++){
            char[] arr = grid[i].toCharArray();
            for(int j = 0; j < n; j++){
            	//获取每一个小小格的索引
                int index = 4 * (i * n + j);
                char c = arr[j];
                //如果是'/'的话,合并0,3和 1,2
                if (c == '/'){
                    uf.union(index, index + 3);
                    uf.union(index + 1, index + 2);
                    //如果是'\\'合并0,1和2,3
                }else if (c =='\\'){
                    uf.union(index, index + 1);
                    uf.union(index + 2, index + 3);
                   //否则四个都合并
                }else{
                    uf.union(index, index + 1);
                    uf.union(index + 1, index + 2);
                    uf.union(index + 2, index + 3);
                }
				//向下向右进行合并
                if (j + 1 < n){
                    uf.union(index + 1, 4 * (i * n + j + 1) + 3);
                }
                if (i + 1 < n){
                    uf.union(index + 2, 4 * ((i + 1) * n + j));
                }
            }
        }
		//最后获取联通分量个数就行,可以在合并过程中维护,也可以最后再算一次。
        return uf.getCount();
    }

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

        public int getCount(){
            return count;
        }

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

        public void union(int x, int y){
            int root1 = find(x);
            int root2 = find(y);
            if (root1 == root2) return;
            parent[root1] = root2;
            count--;
        }
   
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值