Java实现LeetCode 题号:881 - 890

「这是我参与2022首次更文挑战的第34天,活动详情查看:2022首次更文挑战」。

LeetCode习题集 有些题可能直接略过了,整理一下之前刷leetcode

881. 救生艇

难度中等208收藏分享切换为英文接收动态反馈

给定数组 people 。people[i]表示第 i 个人的体重 ,船的数量不限,每艘船可以承载的最大重量为 limit

每艘船最多可同时载两人,但条件是这些人的重量之和最多为 limit

返回 承载所有人所需的最小船数 。

 

示例 1:

输入: people = [1,2], limit = 3
输出: 1
解释: 1 艘船载 (1, 2)
复制代码

示例 2:

输入: people = [3,2,2,1], limit = 3
输出: 3
解释: 3 艘船分别载 (1, 2), (2) 和 (3)
复制代码

示例 3:

输入: people = [3,5,3,4], limit = 5
输出: 4
解释: 4 艘船分别载 (3), (3), (4), (5)
复制代码

 

提示:

  • 1 <= people.length <= 5 * 104
  • 1 <= people[i] <= limit <= 3 * 104
class Solution {
    public int numRescueBoats(int[] num, int limit) {
        Arrays.sort(num);
        int right = num.length - 1;
        int left = 0;
        int res = 0;
        while (left <= right) {
            if (num[left] + num[right] > limit) {
                right--;
                res++;
            } else {
                left++;
                right--;
                res++;
            }
        }
        return res;
    }
}
复制代码

883. 三维形体投影面积

难度简单66收藏分享切换为英文接收动态反馈

在 n x n 的网格 grid 中,我们放置了一些与 x,y,z 三轴对齐的 1 x 1 x 1 立方体。

每个值 v = grid[i][j] 表示 v 个正方体叠放在单元格 (i, j) 上。

现在,我们查看这些立方体在 xy 、yz 和 zx 平面上的投影

投影 就像影子,将 三维 形体映射到一个 二维 平面上。从顶部、前面和侧面看立方体时,我们会看到“影子”。

返回 所有三个投影的总面积 。

 

示例 1:

输入: [[1,2],[3,4]]
输出: 17
解释: 这里有该形体在三个轴对齐平面上的三个投影(“阴影部分”)。
复制代码

示例 2:

输入: grid = [[2]]
输出: 5
复制代码

示例 3:

输入: [[1,0],[0,2]]
输出: 8
复制代码

 

提示:

  • n == grid.length == grid[i].length
  • 1 <= n <= 50
  • 0 <= grid[i][j] <= 50
class Solution {
    public int projectionArea(int[][] grid) {
        int[] x = new int[grid.length];
        int[] y = new int[grid.length];
        int n = grid.length;
        
        int res = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                x[i] = (int)Math.max(x[i], grid[i][j]);
                y[j] = (int)Math.max(y[j], grid[i][j]);
                if (grid[i][j] == 0) {
                    res--;
                }
            }
        }
        for (int i = 0; i < n; i++) {
            res = res + x[i] + y[i];
        }
        return res + n*n;
    }
}
复制代码

884. 两句话中的不常见单词

难度简单154收藏分享切换为英文接收动态反馈

句子 是一串由空格分隔的单词。每个 单词 **仅由小写字母组成。

如果某个单词在其中一个句子中恰好出现一次,在另一个句子中却 没有出现 ,那么这个单词就是 不常见的 **。

给你两个 句子 s1 和 s2 ,返回所有 不常用单词 的列表。返回列表中单词可以按 任意顺序 组织。

 

示例 1:

输入: s1 = "this apple is sweet", s2 = "this apple is sour"
输出: ["sweet","sour"]
复制代码

示例 2:

输入: s1 = "apple apple", s2 = "banana"
输出: ["banana"]
复制代码

 

提示:

  • 1 <= s1.length, s2.length <= 200
  • s1 和 s2 由小写英文字母和空格组成
  • s1 和 s2 都不含前导或尾随空格
  • s1 和 s2 中的所有单词间均由单个空格分隔
class Solution {
    public String[] uncommonFromSentences(String s1, String s2) {
        String[] strs = s1.split(" ");
        Map<String,Integer> map = new HashMap<String,Integer>();
        for (String s : strs) {
            map.put(s,map.getOrDefault(s,0) + 1);
        }
        strs = s2.split(" ");
        for (String s : strs) {
            map.put(s, map.getOrDefault(s,0) + 1);
        }
        List<String> list = new LinkedList<String>();
        for (String s : map.keySet()) {
            if (map.get(s) == 1) {
                list.add(s);
            }
        }
        return list.toArray(new String[list.size()]);
    }
}
复制代码

885. 螺旋矩阵 III

难度中等74收藏分享切换为英文接收动态反馈

在 R 行 C 列的矩阵上,我们从 (r0, c0) 面朝东面开始

这里,网格的西北角位于第一行第一列,网格的东南角位于最后一行最后一列。

现在,我们以顺时针按螺旋状行走,访问此网格中的每个位置。

每当我们移动到网格的边界之外时,我们会继续在网格之外行走(但稍后可能会返回到网格边界)。

最终,我们到过网格的所有 R * C 个空间。

按照访问顺序返回表示网格位置的坐标列表。

 

示例 1:

输入: R = 1, C = 4, r0 = 0, c0 = 0
输出: [[0,0],[0,1],[0,2],[0,3]]
复制代码

 

示例 2:

输入: R = 5, C = 6, r0 = 1, c0 = 4
输出: [[1,4],[1,5],[2,5],[2,4],[2,3],[1,3],[0,3],[0,4],[0,5],[3,5],[3,4],[3,3],[3,2],[2,2],[1,2],[0,2],[4,5],[4,4],[4,3],[4,2],[4,1],[3,1],[2,1],[1,1],[0,1],[4,0],[3,0],[2,0],[1,0],[0,0]]
复制代码

 

提示:

  1. 1 <= R <= 100
  2. 1 <= C <= 100
  3. 0 <= r0 < R
  4. 0 <= c0 < C
class Solution {
    public int[][] spiralMatrixIII(int R, int C, int r0, int c0) {
        int[][] res = new int[R*C][2];
        int[][] around = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
        int x = r0, y = c0, num = 1, dir = 0;  //{x, y}为当前位置,num为当前查找的数字,dir为当前的方向
        int Left = c0 - 1, Right = c0 + 1, Upper = r0 - 1, Bottom = r0 + 1;  //四个方向的边界
        while (num <= R * C) {
            if (x >= 0 && x < R && y >= 0 && y < C) {  //{x, y}位置在矩阵中
                res[num - 1] = new int[]{x, y};
                num++;
            }
            if (dir == 0 && y == Right) {  //向右到右边界
                dir += 1;  //调转方向向下
                Right += 1;  //右边界右移
            }
            else if (dir == 1 &&  x == Bottom) {  //向下到底边界
                dir += 1;
                Bottom += 1;  //底边界下移
            }
            else if (dir == 2 && y == Left) {  //向左到左边界
                dir += 1;
                Left--;  //左边界左移
            }
            else if (dir == 3 && x == Upper) {  //向上到上边界
                dir = 0;
                Upper--;  //上边界上移
            }
            x += around[dir][0];   //下一个节点
            y += around[dir][1];
        }
        return res;
    }
}
复制代码

886. 可能的二分法

难度中等155收藏分享切换为英文接收动态反馈

给定一组 n 人(编号为 1, 2, ..., n), 我们想把每个人分进任意大小的两组。每个人都可能不喜欢其他人,那么他们不应该属于同一组。

给定整数 n 和数组 dislikes ,其中 dislikes[i] = [ai, bi] ,表示不允许将编号为 ai 和  bi的人归入同一组。当可以用这种方法将所有人分进两组时,返回 true;否则返回 false

 

示例 1:

输入: n = 4, dislikes = [[1,2],[1,3],[2,4]]
输出: true
解释: group1 [1,4], group2 [2,3]
复制代码

示例 2:

输入: n = 3, dislikes = [[1,2],[1,3],[2,3]]
输出: false
复制代码

示例 3:

输入: n = 5, dislikes = [[1,2],[2,3],[3,4],[4,5],[1,5]]
输出: false
复制代码

 

提示:

  • 1 <= n <= 2000
  • 0 <= dislikes.length <= 104
  • dislikes[i].length == 2
  • 1 <= dislikes[i][j] <= n
  • ai < bi
  • dislikes 中每一组都 不同
class Solution {
    ArrayList<Integer>[] list;
        Map<Integer,Integer> color;
        
    public boolean possibleBipartition(int n, int[][] bool) {
        list = new ArrayList[n + 1];
        color = new HashMap<Integer,Integer>();
        for (int i = 0; i <= n; i++) {
            list[i] = new ArrayList<Integer>();
        }
        for (int i = 0; i< bool.length; i++) {
            list[bool[i][0]].add(bool[i][1]);
            list[bool[i][1]].add(bool[i][0]);
        }
        for (int node = 1; node <= n; node++) {
            if(!color.containsKey(node)) {
                if(!dfs(node,0)) {
                    return false;
                }
            }
        }
        return true;
    }
    public boolean dfs(int node, int group) {
        if(color.containsKey(node)) {
            return color.get(node) == group;
        }
        color.put(node,group);
        for (int i : list[node]) {
            if(!dfs(i,group ^ 1)) {
                return false;
            }
        }
        return true;

    }
}
复制代码

887. 鸡蛋掉落

难度困难748收藏分享切换为英文接收动态反馈

给你 k 枚相同的鸡蛋,并可以使用一栋从第 1 层到第 n 层共有 n 层楼的建筑。

已知存在楼层 f ,满足 0 <= f <= n ,任何从 高于 f 的楼层落下的鸡蛋都会碎,从 f 楼层或比它低的楼层落下的鸡蛋都不会破。

每次操作,你可以取一枚没有碎的鸡蛋并把它从任一楼层 x 扔下(满足 1 <= x <= n)。如果鸡蛋碎了,你就不能再次使用它。如果某枚鸡蛋扔下后没有摔碎,则可以在之后的操作中 重复使用 这枚鸡蛋。

请你计算并返回要确定 f 确切的值 的 最小操作次数 是多少?

 

示例 1:

输入: k = 1, n = 2
输出: 2
解释:
鸡蛋从 1 楼掉落。如果它碎了,肯定能得出 f = 0 。 
否则,鸡蛋从 2 楼掉落。如果它碎了,肯定能得出 f = 1 。 
如果它没碎,那么肯定能得出 f = 2 。 
因此,在最坏的情况下我们需要移动 2 次以确定 f 是多少。 
复制代码

示例 2:

输入: k = 2, n = 6
输出: 3
复制代码

示例 3:

输入: k = 3, n = 14
输出: 4
复制代码

 

提示:

  • 1 <= k <= 100
  • 1 <= n <= 104
class Solution {
//    public int superEggDrop(int K, int N) {
//         if (N == 1) {
//             return 1;
//         }
//         int[][] f = new int[N + 1][K + 1];
//         for (int i = 1; i <= K; ++i) {
//             f[1][i] = 1;
//         }
//         int ans = -1;
//         for (int i = 2; i <= N; ++i) {
//             for (int j = 1; j <= K; ++j) {
//                 f[i][j] = 1 + f[i - 1][j - 1] + f[i - 1][j];
//             }
//             if (f[i][K] >= N) {
//                 ans = i;
//                 break;
//             }
//         }
//         return ans;
//     }
 public int superEggDrop(int K, int N) {
        int[] dp = new int[K + 1];
        int ans = 0;    // 操作的次数
        while (dp[K] < N){
            for (int i = K; i > 0; i--) // 从后往前计算
                dp[i] = dp[i] + dp[i-1] + 1;
            ans++;
        }
        return ans;
    }
 
}
复制代码

888. 公平的糖果交换

难度简单188收藏分享切换为英文接收动态反馈

爱丽丝和鲍勃拥有不同总数量的糖果。给你两个数组 aliceSizes 和 bobSizes ,aliceSizes[i] 是爱丽丝拥有的第 i 盒糖果中的糖果数量,bobSizes[j] 是鲍勃拥有的第 j 盒糖果中的糖果数量。

两人想要互相交换一盒糖果,这样在交换之后,他们就可以拥有相同总数量的糖果。一个人拥有的糖果总数量是他们每盒糖果数量的总和。

返回一个整数数组 answer,其中 answer[0] 是爱丽丝必须交换的糖果盒中的糖果的数目,answer[1] 是鲍勃必须交换的糖果盒中的糖果的数目。如果存在多个答案,你可以返回其中 任何一个 。题目测试用例保证存在与输入对应的答案。

 

示例 1:

输入: aliceSizes = [1,1], bobSizes = [2,2]
输出: [1,2]
复制代码

示例 2:

输入: aliceSizes = [1,2], bobSizes = [2,3]
输出: [1,2]
复制代码

示例 3:

输入: aliceSizes = [2], bobSizes = [1,3]
输出: [2,3]
复制代码

示例 4:

输入: aliceSizes = [1,2,5], bobSizes = [2,4]
输出: [5,4]
复制代码

 

提示:

  • 1 <= aliceSizes.length, bobSizes.length <= 104
  • 1 <= aliceSizes[i], bobSizes[j] <= 105
  • 爱丽丝和鲍勃的糖果总数量不同。
  • 题目数据保证对于给定的输入至少存在一个有效答案。
class Solution {
    public int[] fairCandySwap(int[] a, int[] b) {
        int sumA = 0, sumB = 0;
        boolean[] bool = new boolean[100001];
        for (int i : a) {
            sumA += i;
            bool[i] = true;
        
        }
        for (int i : b) {
            sumB += i;
        }
        int res = (sumA - sumB) / 2;
        for (int i : b) {
            if (i + res >= 0 && i + res <= bool.length && bool[i + res]) {
                return new int[]{i + res,i};
            }
        }
        return null;


    }
}
复制代码

889. 根据前序和后序遍历构造二叉树

难度中等220收藏分享切换为英文接收动态反馈

给定两个整数数组,preorder 和 postorder ,其中 preorder 是一个具有 无重复 值的二叉树的前序遍历,postorder 是同一棵树的后序遍历,重构并返回二叉树。

如果存在多个答案,您可以返回其中 任何 一个。

 

示例 1:

输入: preorder = [1,2,4,5,3,6,7], postorder = [4,5,2,6,7,3,1]
输出: [1,2,3,4,5,6,7]
复制代码

示例 2:

输入: preorder = [1], postorder = [1]
输出: [1]
复制代码

 

提示:

  • 1 <= preorder.length <= 30
  • 1 <= preorder[i] <= preorder.length
  • preorder 中所有值都 不同
  • postorder.length == preorder.length
  • 1 <= postorder[i] <= postorder.length
  • postorder 中所有值都 不同
  • 保证 preorder 和 postorder 是同一棵二叉树的前序遍历和后序遍历
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public TreeNode constructFromPrePost(int[] pre, int[] post) {
        int n = pre.length;
        if (n == 0) return null;
        TreeNode node = new TreeNode(pre[0]);
        if (n == 1) return node;
        int left = 0;
        for (int i = 0; i < n; i++) {
            if (pre[1] == post[i]) {
                left = i + 1;
            }
        }
        node.left = constructFromPrePost(Arrays.copyOfRange(pre, 1, left + 1), Arrays.copyOfRange(post, 0, left));
        node.right = constructFromPrePost(Arrays.copyOfRange(pre, left + 1, n), Arrays.copyOfRange(post, left, n - 1));
        return node;

    }
}
复制代码

890. 查找和替换模式

难度中等120收藏分享切换为英文接收动态反馈

你有一个单词列表 words 和一个模式  pattern,你想知道 words 中的哪些单词与模式匹配。

如果存在字母的排列 p ,使得将模式中的每个字母 x 替换为 p(x) 之后,我们就得到了所需的单词,那么单词与模式是匹配的。

(回想一下,字母的排列是从字母到字母的双射:每个字母映射到另一个字母,没有两个字母映射到同一个字母。)

返回 words 中与给定模式匹配的单词列表。

你可以按任何顺序返回答案。

 

示例:

输入: words = ["abc","deq","mee","aqq","dkd","ccc"], pattern = "abb"
输出: ["mee","aqq"]
解释: "mee" 与模式匹配,因为存在排列 {a -> m, b -> e, ...}。
"ccc" 与模式不匹配,因为 {a -> c, b -> c, ...} 不是排列。
因为 a 和 b 映射到同一个字母。
复制代码

 

提示:

  • 1 <= words.length <= 50
  • 1 <= pattern.length = words[i].length <= 20
class Solution {
    public List<String> findAndReplacePattern(String[] words, String pattern) {
        ArrayList<String> list = new ArrayList<String>();
        for (String s : words) {
            if (compare(s,pattern)) {
                list.add(s);
            }
        }
        return list;
    }
    public boolean compare(String s1, String s2) {
        char[] str1 = s1.toCharArray();
        char[] str2 = s2.toCharArray();
        Map<Character, Character> map = new HashMap<Character, Character>();
        for (int i = 0; i < str1.length; i++) {
            if (!map.containsKey(str1[i])) map.put(str1[i], str2[i]);
            if (map.get(str1[i]) != str2[i]) return false;
        }
        boolean[] bool = new boolean[26];
        for (char c : map.values()) {
            if(bool[c - 'a']) return false;
            bool[c-'a'] = true;
        }
        return true;
    }
}
复制代码

Guess you like

Origin juejin.im/post/7067041564505145358