leetcode刷题 557~

题目557

反转字符串中的单词III

给定一个字符串,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。

思路实现

class Solution {
    public String reverseWords(String s) {
        String[] buff = s.split(" ");
        StringBuffer result = new StringBuffer();
        for(String string: buff){
            String reverse = new StringBuffer(string).reverse().toString();
            result.append(reverse+" ");
        }
        return result.toString().substring(0, s.length());
    }
}

题目558

四叉树交集

二进制矩阵中的所有元素不是 0 就是 1 。

给你两个四叉树,quadTree1 和 quadTree2。其中 quadTree1 表示一个 n * n 二进制矩阵,而 quadTree2 表示另一个 n * n 二进制矩阵。

请你返回一个表示 n * n 二进制矩阵的四叉树,它是 quadTree1 和 quadTree2 所表示的两个二进制矩阵进行 按位逻辑或运算 的结果。

注意,当 isLeaf 为 False 时,你可以把 True 或者 False 赋值给节点,两种值都会被判题机制 接受 。

四叉树数据结构中,每个内部节点只有四个子节点。此外,每个节点都有两个属性:

val:储存叶子结点所代表的区域的值。1 对应 True,0 对应 False;
isLeaf: 当这个节点是一个叶子结点时为 True,如果它有 4 个子节点则为 False 。

思路

递归

实现

class Solution {
    public Node intersect(Node quadTree1, Node quadTree2) {
        if(quadTree1.isLeaf){
            if(quadTree1.val == true){
                return quadTree1;
            }
            else{
                return quadTree2;
            }
        }else if(quadTree2.isLeaf){
            if(quadTree2.val == true){
                return quadTree2;
            }else{
                return quadTree1;
            }
        }
        Node topLeft = intersect(quadTree1.topLeft, quadTree2.topLeft);
        Node topRight = intersect(quadTree1.topRight, quadTree2.topRight);
        Node bottomLeft = intersect(quadTree1.bottomLeft, quadTree2.bottomLeft);
        Node bottomRight = intersect(quadTree1.bottomRight, quadTree2.bottomRight);
        if(topLeft.isLeaf && topRight.isLeaf && bottomLeft.isLeaf && bottomRight.isLeaf &&topLeft.val && topRight.val && bottomLeft.val && bottomRight.val){
            return new Node(true, true, null, null, null, null);
        }
        return new Node(false, false,topLeft, topRight, bottomLeft, bottomRight);
    }
}

题目559

N叉树的最大深度

给定一个 N 叉树,找到其最大深度。

最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。

思路实现

class Solution {
    private int maxLevel = 0;
    public int maxDepth(Node root) {
        if(root == null){
            return maxLevel;
        }
        dfs(root, 0);
        return maxLevel;
    }

    private void dfs(Node node, int level){
        int curLevel = level +1;
        if(node.children.isEmpty()){
            maxLevel = Math.max(maxLevel, curLevel);
        }else{
            for(Node next: node.children){
                dfs(next, curLevel);
            }
        }
    }
}

题目560

和为k的子数组

给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数。

示例 1 :

输入:nums = [1,1,1], k = 2
输出: 2 , [1,1] 与 [1,1] 为两种不同的情况。

思路

前缀树:

维护一个表,这个表的key是从0到index的和,value是key出现的次数。

实现

class Solution {
    public int subarraySum(int[] nums, int k) {
        HashMap<Integer, Integer> map = new HashMap<>();
        int sum = 0;
        int res = 0;
        map.put(0,1);
        for (int index = 0; index < nums.length; index++ ){
            sum += nums[index];
            int temp = sum - k;
            if(map.containsKey(temp)){
                res += map.get(temp);
            }
            map.put(sum, map.getOrDefault(sum, 0)+1);
        }
        return res;
    }
}

题目561

数组拆分I

给定长度为 2n 的整数数组 nums ,你的任务是将这些数分成 n 对, 例如 (a1, b1), (a2, b2), ..., (an, bn) ,使得从 1 到 n 的 min(ai, bi) 总和最大。

返回该 最大总和 。

思路

排序

实现

class Solution {
    public int arrayPairSum(int[] nums) {
        Arrays.sort(nums);
        int res=0;
        for(int index=0; index < nums.length; index+=2){
            res += nums[index];
        }
        return res;
    }
}

题目563

二叉树的坡度

给定一个二叉树,计算 整个树 的坡度 。

一个树的 节点的坡度 定义即为,该节点左子树的节点之和和右子树节点之和的 差的绝对值 。如果没有左子树的话,左子树的节点之和为 0 ;没有右子树的话也是一样。空结点的坡度是 0 。

整个树 的坡度就是其所有节点的坡度之和。

思路实现

class Solution {
    private int res = 0;
    public int findTilt(TreeNode root) {
        int num = dfs(root);
        return res;
    }

    private int dfs(TreeNode node){
        if(node == null){
            return 0;
        }
        int left = dfs(node.left);
        int right = dfs(node.right);
        res += Math.abs(left-right);
        return node.val+left+right;
    }
}

题目565

数组嵌套

索引从0开始长度为N的数组A,包含0到N - 1的所有整数。找到最大的集合S并返回其大小,其中 S[i] = {A[i], A[A[i]], A[A[A[i]]], ... }且遵守以下的规则。

假设选择索引为i的元素A[i]为S的第一个元素,S的下一个元素应该是A[A[i]],之后是A[A[A[i]]]... 以此类推,不断添加直到S出现重复的元素。

思路

深度优先遍历

实现

class Solution {
    private int[] nums;
    boolean[] visited;
    public int arrayNesting(int[] nums) {
        this.nums = nums;
        visited = new boolean[nums.length];
        int res = 0;
        for(int i=0; i<nums.length; i++){
            if(!visited[i]){
                res = Math.max(dfs(i), res);
            }
        }
        return res;
    }

    public int dfs(int begin){
        visited[begin] = true;
        int nextIndex = nums[begin];
        int num =0;
        if(!visited[nextIndex]){
            num = dfs(nextIndex);
        }
        return 1+num;
    }
}

题目566

重塑矩阵

在MATLAB中,有一个非常有用的函数 reshape,它可以将一个矩阵重塑为另一个大小不同的新矩阵,但保留其原始数据。

给出一个由二维数组表示的矩阵,以及两个正整数r和c,分别表示想要的重构的矩阵的行数和列数。

重构后的矩阵需要将原始矩阵的所有元素以相同的行遍历顺序填充。

如果具有给定参数的reshape操作是可行且合理的,则输出新的重塑矩阵;否则,输出原始矩阵。

思路实现

class Solution {
    public int[][] matrixReshape(int[][] nums, int r, int c) {
        int m = nums.length;
        int n = nums[0].length;
        int count = m*n;
        if(r*c != count){
            return nums;
        }
        int[][] res = new int[r][c];
        for(int i=0; i<count; i++){
            res[i/c][i%c] = nums[i/n][i%n];
        }
        return res;
    }
}

题目567

字符串的排列

给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。

换句话说,第一个字符串的排列之一是第二个字符串的子串。

示例1:

输入: s1 = "ab" s2 = "eidbaooo"
输出: True
解释: s2 包含 s1 的排列之一 ("ba").

思路

用字典和滑动窗口

实现

class Solution {
    public boolean checkInclusion(String s1, String s2) {
        if(s1.length() > s2.length()){
            return false;
        }
        char[] chars1 = s1.toCharArray();
        char[] chars2 = s2.toCharArray();
        int windows = s1.length();
        int[] s1map = new int[26];
        int[] s2map = new int[26];
        for (int i = 0; i < windows; i++) {
            s1map[chars1[i] - 'a']++;
            s2map[chars2[i] - 'a']++;
        }
        int res = 0;
        for(int i=0; i<26; i++){
            if(s1map[i] == s2map[i]){
                res += 1 ;
            }
        }
        for(int i = windows ; i < s2.length(); i++){
            if(res==26){
                return true;
            }
            int r = chars2[i] - 'a', l = chars2[i-windows]-'a';
            s2map[r] += 1;
            if (s2map[r] == s1map[r])
                res += 1;
            else if(s2map[r] == s1map[r]+1)
                res -= 1;
            s2map[l] -= 1;
            if (s2map[l] == s1map[l])
                res += 1;
            else if(s2map[l] == s1map[l]-1)
                res -= 1;
        }
        return res == 26;
    }
}

题目572

另一个树的子树

给定两个非空二叉树 s 和 t,检验 s 中是否包含和 t 具有相同结构和节点值的子树。s 的一个子树包括 s 的一个节点和这个节点的所有子孙。s 也可以看做它自身的一棵子树。

思路

深度优先遍历

准备答案还使用了KMP和哈希表

实现

class Solution {
    public boolean isSubtree(TreeNode s, TreeNode t) {
        if(s == null){
            return false;
        }
        return equals(s, t)||isSubtree(s.left, t) || isSubtree(s.right, t);
    }

    private boolean equals(TreeNode s, TreeNode t){
        if(s == null && t == null){
            return true;
        }
        if(s != null && t != null && s.val == t.val){
            return equals(s.left, t.left) && equals(s.right, t.right);
        }
        return false;
    }

}

题目575

分糖果

给定一个偶数长度的数组,其中不同的数字代表着不同种类的糖果,每一个数字代表一个糖果。你需要把这些糖果平均分给一个弟弟和一个妹妹。返回妹妹可以获得的最大糖果的种类数。

思路实现

class Solution {
    public int distributeCandies(int[] candyType) {
        HashSet < Integer > set = new HashSet < > ();
        for (int candy: candyType) {
            set.add(candy);
        }
        return Math.min(set.size(), candyType.length / 2);
    }
}

题目576

出界的路径数

给定一个 m × n 的网格和一个球。球的起始坐标为 (i,j) ,你可以将球移到相邻的单元格内,或者往上、下、左、右四个方向上移动使球穿过网格边界。但是,你最多可以移动 N 次。找出可以将球移出边界的路径数量。答案可能非常大,返回 结果 mod 10**9 + 7 的值。

思路

1.深度优先遍历,但是会超时

2.动态规划

dp[i][j][k]:表示从(i,j)出发第k步出界的路径总数,等价于从外界出发第k步走到(i,j)的路径总数

状态转移方程

dp[i][j][k] = dp[i-1][j][k-1]+dp[i+1][j][k-1] + dp[i][j-1][k-1]+dp[i][j+1][k-1]

结果
Sum=dp[i][j][k]

实现

1.
class Solution {
    private int m;
    private int n;
    int[][] move = new int[][]{{-1,0},{1,0},{0,-1},{0,1}};
    public int findPaths(int m, int n, int N, int i, int j) {
        this.m = m;
        this.n = n;
        int res = dfs(i,j,N);
        return res;
    }

    public int dfs(int i, int j ,int round){
        int res = 0;
        if (i < 0 || i == m || j < 0 || j ==n ){
            return 1;
        }
        if (round > 0){
            for(int in=0; in<4; in++){
                int x = i + move[in][0];
                int y = j + move[in][1];
                res += dfs(x,y, round-1) % (10**9+7);
            }
        }
        return res;
    }
}
2.class Solution {
    private int m;
    private int n;
    int[][] move = new int[][]{{-1,0},{1,0},{0,-1},{0,1}};
    public int findPaths(int m, int n, int N, int x, int y) {
       long[][][] dp = new long [m+2][n+2][N+1];
       int mod = 1000000007;
       for(int i =0 ; i < m+2; i++){
           dp[i][0][0] = 1;
           dp[i][n+1][0] = 1;
        }
       for(int j=0; j < n+2; j++){
           dp[0][j][0] = 1;
           dp[m+1][j][0] = 1;
        }
        for(int k = 1; k<=N; k++){
            for(int i = 1; i < m+1; i++){
                for(int j=1; j< n+1; j++){
                    dp[i][j][k] = (dp[i-1][j][k-1]+dp[i+1][j][k-1]+dp[i][j-1][k-1]+dp[i][j+1][k-1])%(mod);
                }
            }
        }
        long res =0;
        for(int k=0; k<=N; k++){
            res = (res + dp[x+1][y+1][k]) % mod;
        }
        return (int)res;
    }
}

题目581

最短无序连续子数组

给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。

你找到的子数组应是最短的,请输出它的长度。

示例 1:

输入: [2, 6, 4, 8, 10, 9, 15]
输出: 5
解释: 你只需要对 [6, 4, 8, 10, 9] 进行升序排序,那么整个表都会变为升序排序。

思路

从左到右循环,记录最大值为 max,若 nums[i] < max, 则表明位置 i 需要调整, 循环结束,记录需要调整的最大位置 i 为 high;

同理,从右到左循环,记录最小值为 min, 若 nums[i] > min, 则表明位置 i 需要调整,循环结束,记录需要调整的最小位置 i 为 low.

实现

class Solution {
    public int findUnsortedSubarray(int[] nums) {
        int max = nums[0];
        int high = 0;
        for(int i = 0; i < nums.length; i ++){
            if(nums[i] < max){
                high = i;
            }
            else{
                max = nums[i];
            }
        }
        int min = nums[nums.length-1];
        int low = nums.length -1;
        for(int i = nums.length-1; i>=0; i--){
            if(nums[i] > min){
                low = i;
            }
            else{
                min = nums[i];
            }
        }
        return (low - high +1) == nums.length ? 0 : high - low +1;

    }
}

 

posted @ 2021-01-04 17:03  maoguai  阅读(84)  评论(0编辑  收藏  举报