【每日一题Day2】LC779.第k个语法符号

第k个语法符号【LC779】

我们构建了一个包含 n 行( 索引从 1 开始 )的表。首先在第一行我们写上一个 0。接下来的每一行,将前一行中的0替换为011替换为10

  • 例如,对于 n = 3 ,第 1 行是 0 ,第 2 行是 01 ,第3行是 0110

给定行数 n 和序数 k,返回第 n 行中第 k 个字符。( k 从索引 1 开始

还是只能想到简单的找规律去模拟这个过程,如何把位运算和递归深入骨髓?
加油!努力写出高级的代码

StringBuilder模拟[内存超出限制]

class Solution {
    public int kthGrammar(int n, int k) {
        if (n == 1 && k == 1){
            return 0;
        }
        if (n == 2){
            if (k == 1){
                return 0;
            }else if(k == 2){
                return 1;
            }
        }
        StringBuilder sb = new StringBuilder("01");
        for (int i = 0; i < n - 2; i++){
            for(int j = 0; j < sb.length(); j++){
                if (sb.charAt(j) == '0'){
                    sb.append('1');
                }else{
                    sb.append('0');
                }
            }
        }
        return sb.charAt(k-1) - '0';
    }
}

找规律

  1. 每一行的后半部分正好为前一半取反,前半部分是 0 后半部分变为 1,前半部分是 1,后半部分变为 0。
  2. 那么如果k>1或者n>1,那么证明k在某个对称轴后半部分,可以进行取反,这个对称轴为小于k的最大的2n,k-=2n,标记flag取反
  3. 最后如果flag为true,表明不需取反,返回0;flag为false,表明需要取反,返回1
  • 代码

    class Solution {
        public int kthGrammar(int n, int k) {
            Boolean flag = true; // 当flag为true时,不需要取反;当flag为false时,需要取反;
            // while (k > 1){// 能够对称反转
            //     while (Math.pow(2,n) >= k){
            //         n--;
            //     }
            //     k -= Math.pow(2,n);
            //     flag = !flag;
            // }
            while (n > 1){
                if (k > Math.pow(2,n-2)){
                    flag = !flag;
                    k -= Math.pow(2,n-2);
                }
                n--;
            }
            return flag ? 0 : 1;
        }
    }
    
  • 复杂度分析

    • 时间复杂度:O(n),其中 n为行数。
    • 空间复杂度:O(1)。

正向递归

class Solution {
    public int kthGrammar(int n, int k) {
        return dfs(n,k);
    }
    public int dfs(int n, int k){
        if (n == 1){
            return 0;
        }
        int len = (int)(Math.pow(2,n - 2));// 上一行的长度
        if (k <= len){// 前半段
            return dfs(n - 1, k);
        }else{
            return dfs(n - 1, k - len) == 0 ? 1 : 0;// 后半段 取反
        }
    }
}
  • 复杂度分析
    • 时间复杂度:O(n),其中 n为行数。
    • 空间复杂度:O(n),递归的空间开销

逆向递归

假设第 n 行 第 k 个元素是 1,开始验证,直到最底层(第 1 行),如果一样,说明就是返回当前元素,否则返回相反元素。

class Solution {
    public int kthGrammar(int n, int k) {
        return dfs(n, k, 1) == 0 ? 1 : 0;
    }
    int dfs(int r, int c, int cur) {
        if (r == 1) return cur;
        if ((c % 2 == 0 && cur == 0) || (c % 2 == 1 && cur == 1)) return dfs(r - 1, (c - 1) / 2 + 1, 1);
        else return dfs(r - 1, (c - 1) / 2 + 1, 0);
    }
}

作者:宫水三叶
链接:https://leetcode.cn/problems/k-th-symbol-in-grammar/solutions/1906532/by-ac_oier-fp2f/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

正向递归+位运算

1 << (n - 2) : pow(2,n-2)

1 ^ n :本题可以达到取反的功能

class Solution {
    public int kthGrammar(int n, int k) {
        if (k == 1) {
            return 0;
        }
        if (k > (1 << (n - 2))) {
            return 1 ^ kthGrammar(n - 1, k - (1 << (n - 2)));
        }
        return kthGrammar(n - 1, k);
    }
}

作者:力扣官方题解
链接:https://leetcode.cn/problems/k-th-symbol-in-grammar/solutions/1903508/di-kge-yu-fa-fu-hao-by-leetcode-solution-zgwd/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值