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; } }