Jerry's Blog

Recording what I learned everyday

View on GitHub


10 October 2019

LeetCode(33) -- 748, 754, 762, 766, 783

by Jerry Zhang

P748. Shortest Completing Word (Easy)

找出最短的包含有牌照里所有字母的单词,忽略大小写。

我的思路

先处理一下牌照,把数据清洗干净,有两个方案,一是形成一个小写26个字母的int数组,记录每个字母出现的次数。在单词中如果出现了某个字母,就去字母表中查找,如果有就减1,最后查一遍26个字母的次数是否都变成了0。

第二个方案是牌照做成一个List, 单词中的每个字母都到这个list里查一遍,包含的话就删掉,最后看它的长度是否变成了0。

因为本身牌照最多6个字母,单词也不超过15个字母。纠结了半天,感觉还是第一个方案会快一点。

我的代码

public class E_748_ShortestCompletingWord {
    public String shortestCompletingWord(String licensePlate, String[] words) {
        int minLength = Integer.MAX_VALUE;
        String ans = null;
        int[] alphabet = new int[26];
        char[] chars = licensePlate.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            if (chars[i] >= 65 && chars[i] <= 90) {
                alphabet[chars[i] - 65]++;
            } else if (chars[i] >= 97 && chars[i] <= 122) {
                alphabet[chars[i] - 97]++;
            }
        }
        for (int i = 0; i < words.length; i++) {
            int[] copyOfAlphabet = alphabet.clone();
            String word = words[i];
            char[] wordChars = word.toCharArray();
            for (int j = 0; j < wordChars.length; j++) {
                if (copyOfAlphabet[wordChars[j] - 97] > 0) {
                    copyOfAlphabet[wordChars[j] - 97]--;
                }
            }
            boolean complete = true;
            for (int j = 0; j < copyOfAlphabet.length; j++) {
                if (copyOfAlphabet[j] != 0) {
                    complete = false;
                }
            }
            if (complete && word.length() < minLength) {
                minLength = word.length();
                ans = word;
            }
        }
        return ans;
    }
}

47%

最优解

class Solution {
    public String shortestCompletingWord(String licensePlate, String[] words) {
        char[] cs = licensePlate.toCharArray();
        int size = 0;
        StringBuilder sb = new StringBuilder();
        for (char c : cs) {
            char key = '0';
            if (c >= 97 && c <= 122) {
                key = c;
            } else if (c >= 65 && c <= 90) {
                key = (char)(c + 32);
            }
            if (key != '0') {
                sb.append(key);
            }

        }

        String check = sb.toString();
        String result = null;
        int lgth = Integer.MAX_VALUE;
        for (String word : words) {
            if (word.length() < lgth && judge(check, word)) {
                result = word;
                lgth = word.length();
            }
        }
        return result;
    }

    private boolean judge(String ck, String wd) {
        if (wd.length() < ck.length()) {
            return false;
        }
        int[] ls = new int[26];
        for (char c : wd.toCharArray()) {
            ls[c - 'a'] ++;
        }
        for (char c : ck.toCharArray()) {
            if (ls[c - 'a'] == 0) {
                return false;
            }
            ls[c - 'a'] --;
        }
        return true;
    }
}

他把牌照清洗后放到一个String里面,然后先把单词做成字母频率数组。再去查牌照中的每个字母,如果没有就直接返回false了。这样比我最后再查一遍是否全是0要方便。还有一点值得学习的是,先查长度,只有长度比最小值还小时,再去查。这样大部分长单词就根本不用查了。

P754. Reach a Number (Easy)

在一个数轴上,可向左或向右移动。第n次可移动n个单位。问最少多少步可以移动到目标值。

我的思路

我一开始想先移动到接近目标值的地方,再一步一步往右走。结果是错的。

看了答案,最重要的一个概念就是,向右加到某个值时如果超过了target,就要看它跟target差多少,也就是超出了多少。如果超出的是偶数,那就直接得到答案了。因为我们只需要把前面的某个数从正数改成负数,结果就会减掉一个偶数。

如果差奇数,就再往前走一步。如果依然差奇数,就再往前走一步,就必然差偶数了。

答案

class Solution {
    public int reachNumber(int target) {
        target = Math.abs(target);
        int k = 0;
        while (target > 0)
            target -= ++k;
        return target % 2 == 0 ? k : k + 1 + k % 2;
    }
}

最优解

class Solution {
    /** 参考花花  */
    public int reachNumber(int target) {
        target = Math.abs(target);
        int k = (int)Math.sqrt(target*2);
        while(sum(k) < target) k++;
        int d = sum(k)-target;
        if(d%2 == 0) return k;
        return k+1+(k%2);
    }
    /** 分析:
        math题目
        看数据规模,应该不能用BFS或racing car的方法
    */

    private int sum(int k) {
        return k*(k+1)/2;
    }
}

P762. Prime Number of Set Bits in Binary Representation (Easy)

给两个整数L和R,代表一个范围。求在这个范围内的整数中,换成二进制后1的个数为质数的数有几个

我的思路

把前31个数全列出来,发现每增加一位数,其实就是上面所有的结果分别加1。

我的代码

public class E_762_PrimeNumberOfSetBitsInBinaryRepresentation {
    public int countPrimeSetBits(int L, int R) {
        int count = 0;
        for (int i = L; i <= R; i++) {
            if(isPrime(setBits(i))) {
                count++;
            }
        }
        return count;
    }

    private int setBits(int n) {
        if (n == 0) return 0;
        if (n == 1) return 1;
        int power = 1;
        while (n - power >= 0) {
            power *= 2;
        }
        return setBits(n - power / 2) + 1;
    }

    private boolean isPrime(int n) {
        if(n < 2) return false;
        if(n == 2) return true;
        if(n % 2 == 0) return false;

        for(int i = 3; i * i <= n; i += 2) {
            if(n % i == 0) return false;
        }
        return true;
    }

}

11%

最优解

class Solution {
    public int countPrimeSetBits(int l, int r) {
        int cnt = 0;
        for (int i = l; i <= r; i++) {
            int bits = Integer.bitCount(i);
            cnt += (665772 & (1 << bits)) != 0 ? 1 : 0;
        }
        return cnt;
    }
}

答案

class Solution {
    public int countPrimeSetBits(int L, int R) {
        int ans = 0;
        for (int x = L; x <= R; ++x)
            if (isSmallPrime(Integer.bitCount(x)))
                ans++;
        return ans;
    }
    public boolean isSmallPrime(int x) {
        return (x == 2 || x == 3 || x == 5 || x == 7 ||
                x == 11 || x == 13 || x == 17 || x == 19);
    }
}

P766. Toeplitz Matrix (Easy)

矩阵,从左上到右下所有斜线的值都一样,就叫Toeplitz

我的思路

以第一行和第一列为起点,分别往右下方递归,确定这一条斜线值一样就返回true。所有斜线全是true,整个函数才返回true。

我的代码

class Solution {
    public boolean isToeplitzMatrix(int[][] matrix) {
        for (int i = 0; i < matrix.length; i++) {
            if (!oneLine(matrix, i, 0)) return false;
        }
        for (int i = 0; i < matrix[0].length; i++) {
            if (!oneLine(matrix, 0, i)) return false;
        }
        return true;
    }

    private boolean oneLine(int[][] matrix, int row, int col) {
        if (row >= matrix.length - 1 || col >= matrix[0].length - 1) return true;
        return matrix[row][col] == matrix[row + 1][col + 1] && oneLine(matrix, row + 1, col + 1);
    }
}

100%

最优解

class Solution {
    private boolean checkDR(int[][] matrix, int sr, int sc) {
        for (int i = sr; i < matrix.length - 1; i++) {
            for (int j = sc; j < matrix[i].length - 1; j++) {
                if (matrix[i + 1][j + 1] != matrix[i][j])
                    return false;
            }
        }
        return true;
    }

    public boolean isToeplitzMatrix(int[][] matrix) {
        int m = matrix.length, n = matrix[0].length;
        for (int i = m - 1; i >= 0; i--) {
            if (!checkDR(matrix, i, 0)) return false;
        }

        for (int i = 1; i < n; i++) {
            if (!checkDR(matrix, 0, i)) return false;
        }

        return true;
    }
}

答案

class Solution {
    public boolean isToeplitzMatrix(int[][] matrix) {
        for (int r = 0; r < matrix.length; ++r)
            for (int c = 0; c < matrix[0].length; ++c)
                if (r > 0 && c > 0 && matrix[r-1][c-1] != matrix[r][c])
                    return false;
        return true;
    }
}

P783. Minimum Distance Between BST Nodes (Easy)

返回一个BST任意两个节点的差的最小值。

我的思路

中序遍历然后记录下最小值。

我的代码

public class E_783_MinimumDistanceBetweenBSTNodes {
    int min = Integer.MAX_VALUE;
    Integer prev = null;
    public int minDiffInBST(TreeNode root) {
        inorder(root);
        return min;
    }

    private void inorder(TreeNode node) {
        if (node == null) {
            return;
        }
        inorder(node.left);
        if (prev == null) {
            prev = node.val;
        } else {
            if (node.val - prev < min) {
                min = node.val - prev;
            }
            prev = node.val;
        }
        inorder(node.right);
    }

}

100% 一次过

最优解

class Solution {
    Integer prev;
    int min = Integer.MAX_VALUE;
    public void inOrder(TreeNode root){
        if(root==null) return;
        inOrder(root.left);
        if(prev!=null){
            min = Math.min(min,Math.abs(root.val-prev));
        }
        prev=root.val;
        inOrder(root.right);
    }
    public int minDiffInBST(TreeNode root) {
        inOrder(root);
        return min;

    }
}

这个代码看着更漂亮,因为无论如何都要更新prev,只是当prev不是第一个时,我才去比较。

tags: LeetCode