题目538题
把二叉搜素树转换为累加树
给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。
提醒一下,二叉搜索树满足下列约束条件:
节点的左子树仅包含键 小于 节点键的节点。
节点的右子树仅包含键 大于 节点键的节点。
左右子树也必须是二叉搜索树。
思路
深度优先遍历
实现
class Solution { public TreeNode convertBST(TreeNode root) { int a = dfs(root,0); return root; } private int dfs(TreeNode node, int bigger){ int right = 0; if(node == null){ return 0; } right = dfs(node.right, bigger); if(node.right == null) node.val += bigger; node.val += right; int left = dfs(node.left, node.val); if(left != 0){ return left; } return node.val; } }
题目539题
最小时间差
给定一个 24 小时制(小时:分钟 "HH:MM")的时间列表,找出列表中任意两个时间的最小时间差并以分钟数表示。
思路实现
class Solution { public int findMinDifference(List<String> timePoints) { if (timePoints.size()>=1440){ return 0; } int[] timeList = new int[timePoints.size()]; for(int index=0; index < timePoints.size(); index++){ String[] time = timePoints.get(index).split(":"); int hour = Integer.parseInt(time[0]); int minute = Integer.parseInt(time[1]); timeList[index] = hour*60 + minute; } Arrays.sort(timeList); int res = 1440; for(int index=1; index < timePoints.size(); index++){ res = Math.min(res, timeList[index]- timeList[index-1]); if(res == 0){ return 0; } } res = Math.min(res, 1440 - timeList[timeList.length - 1] + timeList[0]); return res; } }
题目540题
有序数组中的单一元素
给定一个只包含整数的有序数组,每个元素都会出现两次,唯有一个数只会出现一次,找出这个数。
示例 1:
输入: [1,1,2,3,3,4,4,8,8]
输出: 2
思路
二分法
实现
class Solution { public int singleNonDuplicate(int[] nums) { int left =0, right = nums.length -1; int mid=0; while(left < right){ if(nums[left] != nums[left+1]){ mid = left; break; }else if(nums[right] != nums[right-1]){ mid = right; break; }else{ mid = left + (right-left)/2; } int halflen = (right - left)/2; if(halflen %2==0 && nums[mid]==nums[mid-1]){ right = mid - 2; }else if(halflen %2==0 && nums[mid]==nums[mid+1]){ left = mid + 2; }else if(halflen %2==1 && nums[mid]==nums[mid-1]){ left = mid + 1; }else if(halflen %2==1 && nums[mid]==nums[mid+1]){ right = mid - 1; }else{ break; } } return nums[mid]; } }
题目541题
反转字符串II
给定一个字符串 s 和一个整数 k,你需要对从字符串开头算起的每隔 2k 个字符的前 k 个字符进行反转。
如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
示例:
输入: s = "abcdefg", k = 2
输出: "bacdfeg"
思路实现
class Solution { public String reverseStr(String s, int k) { char[] c = s.toCharArray(); for(int index = 0; index < c.length; index += 2*k){ int i = index, j = Math.min(index + k - 1, c.length - 1); while (i < j) { char tmp = c[i]; c[i++] = c[j]; c[j--] = tmp; } } return String.valueOf(c); } }
题目542题
01矩阵
给定一个由 0 和 1 组成的矩阵,找出每个元素到最近的 0 的距离。
两个相邻元素间的距离为 1 。
示例 1:
输入:
[[0,0,0],
[0,1,0],
[0,0,0]]
输出:
[[0,0,0],
[0,1,0],
[0,0,0]]
思路
1. 深度优先遍历
实现
class Solution { private int[][] matrix; private int row, col; int [][]dirs={{-1,0},{1,0},{0,-1},{0,1}}; public int[][] updateMatrix(int[][] matrix) { this.matrix = matrix; row = matrix.length; col = matrix[0].length; for(int i=0; i < row; i++){ for(int j=0; j < col; j++ ){ if(this.matrix[i][j] ==1 && !hasNeighbors0(i,j)){ this.matrix[i][j] = Integer.MAX_VALUE; } } } for(int i=0; i < row; i++){ for(int j=0; j < col; j++ ){ if(this.matrix[i][j] == 1){ dfs(i, j); } } } return this.matrix; } boolean hasNeighbors0(int x,int y){ for(int[] dir:dirs){ int new_x=x+dir[0]; int new_y=y+dir[1]; if(new_x>=0 && new_x<row && new_y>=0 && new_y<col && matrix[new_x][new_y]==0) return true; } return false; } private void dfs(int x ,int y){ for(int[] dir:dirs){ int new_x=x+dir[0]; int new_y=y+dir[1]; if(new_x>=0 && new_x<row && new_y>=0 && new_y<col && matrix[new_x][new_y]>matrix[x][y]+1 ){ matrix[new_x][new_y] = matrix[x][y]+1; dfs(new_x, new_y); } } } }
题目543题
二叉树的直径
给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。
示例 :
给定二叉树
1
/
2 3
/
4 5
返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。
思路实现
class Solution { int res = 1; public int diameterOfBinaryTree(TreeNode root) { calcLen(root); return res-1; } private int calcLen(TreeNode node){ if (node == null){ return 0; } int resleft = calcLen(node.left); int resright = calcLen(node.right); res = Math.max(resleft + resright+ 1, res); return Math.max(resleft, resright)+1; } }
题目547题
朋友圈
班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。
给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。
思路
1.广度优先遍历
2.Union-Find算法
实现
1. class Solution { public int findCircleNum(int[][] M) { int N = M.length; int res = 0; boolean[] visited = new boolean[N]; Queue<Integer> queue = new LinkedList<Integer>(); for(int i=0; i < N; i++){ if(visited[i] == false){ res +=1; queue.offer(i); while(queue.size()!= 0){ int j = queue.poll(); visited[j] = true; for(int k=0; k <N; k++){ if(M[j][k] == 1 && visited[k] == false){ queue.offer(k); } } } } } return res; } }
2.
题目551题
学生出勤记录I
给定一个字符串来代表一个学生的出勤记录,这个记录仅包含以下三个字符:
'A' : Absent,缺勤
'L' : Late,迟到
'P' : Present,到场
如果一个学生的出勤记录中不超过一个'A'(缺勤)并且不超过两个连续的'L'(迟到),那么这个学生会被奖赏。
你需要根据这个学生的出勤记录判断他是否会被奖赏。
思路实现
class Solution { public boolean checkRecord(String s) { char[] c = s.toCharArray(); int a = 0; int l = 0; for(char i: c){ if(i == 'A'){ a += 1; l = 0; }else if(i == 'L'){ l += 1; }else{ l = 0; } if(a > 1 || l >2){ return false; } } return true; } }
题目553题
最优除法
给定一组正整数,相邻的整数之间将会进行浮点除法操作。例如, [2,3,4] -> 2 / 3 / 4 。
但是,你可以在任意位置添加任意数目的括号,来改变算数的优先级。你需要找出怎么添加括号,才能得到最大的结果,并且返回相应的字符串格式的表达式。你的表达式不应该含有冗余的括号。
示例:
输入: [1000,100,10,2]
输出: "1000/(100/10/2)"
解释:
1000/(100/10/2) = 1000/((100/10)/2) = 200
但是,以下加粗的括号 "1000/((100/10)/2)" 是冗余的,
因为他们并不影响操作的优先级,所以你需要返回 "1000/(100/10/2)"。
思路
数学降维打击:为了最大化 a/b/c/da/b/c/d 我们首先需要最小化 b/c/d,现在我们的目标变成了最小化表达式 b/c/d。而b/c/d就是最小值。因此对于形如 a/b/c/d/e/f... 的表达式,答案将是 a/(b/c/d/e/f...)
实现
class Solution { public String optimalDivision(int[] nums) { if (nums.length == 1) return nums[0] + ""; if (nums.length == 2) return nums[0] + "/" + nums[1]; StringBuilder res = new StringBuilder(nums[0] + "/(" + nums[1]); for (int i = 2; i < nums.length; i++) { res.append("/" + nums[i]); } res.append(")"); return res.toString(); } }
题目554题
砖墙
你的面前有一堵矩形的、由多行砖块组成的砖墙。 这些砖块高度相同但是宽度不同。你现在要画一条自顶向下的、穿过最少砖块的垂线。
砖墙由行的列表表示。 每一行都是一个代表从左至右每块砖的宽度的整数列表。
如果你画的线只是从砖块的边缘经过,就不算穿过这块砖。你需要找出怎样画才能使这条线穿过的砖块数量最少,并且返回穿过的砖块数量。
你不能沿着墙的两个垂直边缘之一画线,这样显然是没有穿过一块砖的。
示例:
输入: [[1,2,2,1],
[3,1,2],
[1,3,2],
[2,4],
[3,1,2],
[1,3,1,1]]
输出: 2
思路
哈希表
实现
class Solution { public int leastBricks(List<List<Integer>> wall) { HashMap<Integer, Integer> map = new HashMap<Integer, Integer>(); int sum = 0; List<Integer> first = wall.get(0); for(int num: first){ sum += num; } for(List<Integer> level: wall){ int cur = 0; for(int num: level){ cur += num; if(cur < sum) map.put(cur,1 + map.getOrDefault(cur,0)); } } int max = 0; for(int num: map.values()){ max = Math.max(max, num); } return wall.size() - max; } }
题目556题
下一个更大元素III
给定一个32位正整数 n,你需要找到最小的32位整数,其与 n 中存在的位数完全相同,并且其值大于n。如果不存在这样的32位整数,则返回-1。
示例 1:
输入: 12
输出: 21
思路实现
class Solution { public int nextGreaterElement(int n) { int[] t = new int[10]; int l = t.length; int temp = n; while (l > 0 && temp > 0) { l--; t[l] = temp % 10; temp /= 10; } for(int i = t.length-1; i >l; i--){ if(t[i-1] < t[i]){ temp = i-1; int w = i-1; int[] min = new int[t.length-i]; int k = 0; for(int j = t.length-1; j>w; j--){ if(t[j] <= t[temp] || temp != i-1){ min[k] = t[j]; k += 1; }else{ min[k] = t[temp]; k += 1; temp = j; } } t[w] = t[temp]; for(int q = i, s=0; q<t.length; q++,s++){ t[q] = min[s]; } break; } } int res = 0; for(int i: t){ res = res*10+i; } return res <= n ? -1 : res; } }