Leetcode刷题 2021.02.26

博客分享了三道Leetcode题的解题思路。包括Leetcode1178猜字谜,需判断单词是否符合条件作为谜底;Leetcode869重新排序得到2的幂,通过枚举2的幂集合比对;Leetcode1676二叉树的最近公共祖先IV,求多个节点的最近公共祖先。

Leetcode1178 猜字谜

外国友人仿照中国字谜设计了一个英文版猜字谜小游戏,请你来猜猜看吧。

字谜的迷面 puzzle 按字符串形式给出,如果一个单词 word 符合下面两个条件,那么它就可以算作谜底:

单词 word 中包含谜面 puzzle 的第一个字母。
单词 word 中的每一个字母都可以在谜面 puzzle 中找到。
例如,如果字谜的谜面是 “abcdefg”,那么可以作为谜底的单词有 “faced”, “cabbage”, 和 “baggage”;而 “beefed”(不含字母 “a”)以及 “based”(其中的 “s” 没有出现在谜面中)都不能作为谜底。
返回一个答案数组 answer,数组中的每个元素 answer[i] 是在给出的单词列表 words 中可以作为字谜迷面 puzzles[i] 所对应的谜底的单词数目。

感觉过个节日就要来个相关的困难题来做。这题如果没有时间限制的话其实是比较简单的,但是纯暴力的话一定会超时。想到位运算,但是怎么处理就想不出来了。看了题解,觉得这些困难题真的是很巧妙啊。

class Solution {
    public List<Integer> findNumOfValidWords(String[] words, String[] puzzles) {
        List<Integer> res = new ArrayList<>();
        Map<Integer, Integer> map = new HashMap<>();
        //先把每个word用一个整型值来表示,因为只关注有没有,不关心数量
        for(String word : words){
            char[] arr = word.toCharArray();
            int temp = 0;
            for(int j = 0; j < arr.length; j++){
                temp |= 1 << arr[j] -'a';
            }
            map.put(temp, map.getOrDefault(temp, 0) + 1);
        }

        for(String s : puzzles){
            char[] arr = s.toCharArray();
            int temp = 0;
            for(int j = 0; j < arr.length; j++){
                temp |= 1 << arr[j] -'a';
            }
            int count = 0;
            //由于每个puzzle只有7位,所以可以对他进行枚举,枚举所有的子集,再看是否存在这样的word就行了
            //这里j = (j - 1) & temp就表示枚举的子集,很巧妙。-1 本身有可能导致出现新的1 ,但是 &k之后又保证了1已然停留在子集里面。
            for(int j = temp; j > 0; j = (j - 1) & temp){
                if ((1 << (arr[0] - 'a') & j) != 0) count += map.getOrDefault(j, 0);
            }
            res.add(count);
        }
        return res;
    }
}

Leetcode869 重新排序得到 2 的幂

给定正整数 N ,我们按任何顺序(包括原始顺序)将数字重新排序,注意其前导数字不能为零。

如果我们可以通过上述方式得到 2 的幂,返回 true;否则,返回 false。

这题因为有数据限制,所以想法就是先直接枚举2的幂的所有集合,在一个个比对就行了。因为10^9以内2的幂最多也就几十个,所以还是可以通过的。

class Solution {
    public boolean reorderedPowerOf2(int N) {
        char[] arr = String.valueOf(N).toCharArray();
        List<Integer> list = new ArrayList<>();
        int i = 0, sum = 0;
        //先枚举所有2的幂
        while (sum <= 1_000_000_000){
            sum = (int)Math.pow(2, i);
            i++;
            list.add(sum);
        }
        for(int ele : list){
            char[] temp = String.valueOf(ele).toCharArray();
            if (temp.length != arr.length) continue;
            if (temp.length > arr.length) break;
            int[] map1 = new int[10];
            int[] map2 = new int[10];
            //进行比对,看看数量是否相同
            if (check(arr, temp)) return true;
        }
        return false;
    }

    private boolean check(char[] arr, char[] temp){
        int[] map1 = new int[10];
        int[] map2 = new int[10];
        for(int i = 0; i < arr.length; i++){
            map1[arr[i] - '0']++;
            map2[temp[i] - '0']++;
        }
        for(int i = 0; i < 10; i++){
            if (map1[i] != map2[i]) return false;
        }
        return true;
    }
}

Leetcode1676 二叉树的最近公共祖先 IV

给定一棵二叉树的根节点 root 和 TreeNode 类对象的数组(列表) nodes,返回 nodes 中所有节点的最近公共祖先(LCA)。数组(列表)中所有节点都存在于该二叉树中,且二叉树中所有节点的值都是互不相同的。

我们扩展二叉树的最近公共祖先节点在维基百科上的定义:“对于任意合理的 i 值, n 个节点 p1 、 p2、…、 pn 在二叉树 T 中的最近公共祖先节点是后代中包含所有节点 pi 的最深节点(我们允许一个节点是其自身的后代)”。一个节点 x 的后代节点是节点 x 到某一叶节点间的路径中的节点 y。

这题和最近公共祖先类似,但是好像想的太复杂了,才击败百分之二十。

class Solution {
    TreeNode res;
    Set<TreeNode> set;
    boolean flag;
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode[] nodes) {
        if (nodes.length == 0) return null;
        if (nodes.length == 1) return nodes[0];
        set = new HashSet<>();
        int n = nodes.length;
        //先把要查找的放到set里面方便查找
        for(TreeNode node : nodes){
            set.add(node);
        }
        helper(root, n);
        return res;
    }

    private int helper(TreeNode root, int target){
        if (root == null) return 0;
        //查找左右子树含有node节点的数量,如果加起来相同就说明该节点是最近公共祖先了
        int l = helper(root.left, target);
        int r = helper(root.right, target);
        int sum = l + r;
        if (set.contains(root)) sum++;
        if (sum == target && !flag){
            res = root;
            flag = true;
        }

        return sum;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值