leetcode刷题 583~
题目583
两个字符串的删除操作
给定两个单词 word1 和 word2,找到使得 word1 和 word2 相同所需的最小步数,每步可以删除任意一个字符串中的一个字符。
示例:
输入: "sea", "eat"
输出: 2
解释: 第一步将"sea"变为"ea",第二步将"eat"变为"ea"
思路
这道题的本质是求两个字符串的最大公共子序列,采用动态规划的方式:
dp[i][j]表示str1[0:i]与str2[0:j]的公共子序列长度
若str1[i]==str2[j] dp[i][j] = dp[i-1][j-1]+1,否则dp[i][j] = max(dp[i-1][j], dp[i][j-1])
实现
class Solution { public int minDistance(String word1, String word2) { int M = word1.length(); int N = word2.length(); char[] list1 = word1.toCharArray(); char[] list2 = word2.toCharArray(); int[][] dp = new int[M+1][N+1]; int res = 0; for(int i=0; i<M; i++){ for(int j=0; j<N; j++){ if(list1[i] == list2[j]) dp[i+1][j+1] = dp[i][j] +1; else dp[i+1][j+1] = Math.max(dp[i+1][j],dp[i][j+1]); } } return M+N- 2*dp[M][N]; } }
题目589
N叉树的前序遍历
给定一个 N 叉树,返回其节点值的前序遍历。
思路实现
class Solution { public List<Integer> preorder(Node root) { List<Integer> res = new ArrayList<>(); if(root == null){ return res; } res.add(root.val); for(Node child: root.children){ res.addAll(preorder(child)); } return res; } }
题目590
N叉树的后序遍历
给定一个 N 叉树,返回其节点值的后序遍历。
思路实现
class Solution { public List<Integer> postorder(Node root) { LinkedList<Integer> res = new LinkedList<>(); Stack<Node> stack = new Stack<>(); if(root == null){ return res; } stack.push(root); while(!stack.isEmpty()){ Node cur = stack.pop(); res.addFirst(cur.val); for(Node child: cur.children){ stack.push(child); } } return res; } }
题目593
有效的正方形
给定二维空间中四点的坐标,返回四点是否可以构造一个正方形。
一个点的坐标(x,y)由一个有两个整数的整数数组表示。
思路
任选三个点都是直角三角形
实现
public class Solution { public boolean validSquare(int[] p1, int[] p2, int[] p3, int[] p4) { return isRightTriangle(p1, p2, p3) && isRightTriangle(p1, p2, p4) && isRightTriangle(p1, p3, p4) && isRightTriangle(p2, p3, p4); } public boolean isRightTriangle(int[] p1, int[]p2, int[] p3){ int d1 = (p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1]); int d2 = (p2[0] - p3[0]) * (p2[0] - p3[0]) + (p2[1] - p3[1]) * (p2[1] - p3[1]); int d3 = (p3[0] - p1[0]) * (p3[0] - p1[0]) + (p3[1] - p1[1]) * (p3[1] - p1[1]); if(d1 > d2 && d2 == d3 && d2 + d3 == d1 || d2 > d1 && d1 == d3 && d1 + d3 == d2 || d3 > d1 && d1 == d2 && d1 + d2 == d3){ return true; } return false; } }
题目594
最长和谐子序列
和谐数组是指一个数组里元素的最大值和最小值之间的差别正好是1。
现在,给定一个整数数组,你需要在所有可能的子序列中找到最长的和谐子序列的长度。
思路实现
class Solution { public int findLHS(int[] nums) { int res = 0; HashMap<Integer, Integer> map = new HashMap<>(); for(int num: nums){ map.put(num, map.getOrDefault(num, 0)+1); } for(int key: map.keySet()){ int val = map.get(key); int max = map.getOrDefault(key+1, 0); if(max != 0) res = Math.max(res, max+val); } return res; } }
题目598
范围求和II
给定一个初始元素全部为 0,大小为 m*n 的矩阵 M 以及在 M 上的一系列更新操作。
操作用二维数组表示,其中的每个操作用一个含有两个正整数 a 和 b 的数组表示,含义是将所有符合 0 <= i < a 以及 0 <= j < b 的元素 M[i][j] 的值都增加 1。
在执行给定的一系列操作后,你需要返回矩阵中含有最大整数的元素个数。
思路实现
class Solution { public int maxCount(int m, int n, int[][] ops) { if(ops.length == 0){ return m*n; } int a = Integer.MAX_VALUE; int b = Integer.MAX_VALUE; for(int[] op : ops){ a = Math.min(a, op[0]); b = Math.min(b, op[1]); } return a*b; } }
题目599
两个列表的最小索引和
假设Andy和Doris想在晚餐时选择一家餐厅,并且他们都有一个表示最喜爱餐厅的列表,每个餐厅的名字用字符串表示。
你需要帮助他们用最少的索引和找出他们共同喜爱的餐厅。 如果答案不止一个,则输出所有答案并且不考虑顺序。 你可以假设总是存在一个答案。
示例 1:
输入:
["Shogun", "Tapioca Express", "Burger King", "KFC"]
["Piatti", "The Grill at Torrey Pines", "Hungry Hunter Steakhouse", "Shogun"]
输出: ["Shogun"]
解释: 他们唯一共同喜爱的餐厅是“Shogun”。
思路
哈希表
实现
class Solution { public String[] findRestaurant(String[] list1, String[] list2) { HashMap < Integer, List < String >> map = new HashMap < > (); int min = Integer.MAX_VALUE; for (int i = 0; i < list1.length; i++) { for (int j = 0; j < list2.length; j++) { if (list1[i].equals(list2[j])) { if (!map.containsKey(i + j)) map.put(i + j, new ArrayList <String> ()); map.get(i + j).add(list1[i]); min = Math.min(min, i+j); } } } String[] res = map.get(min).toArray(new String[map.get(min).size()]); return res; } }
题目605
种花问题
假设有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花不能种植在相邻的地块上,它们会争夺水源,两者都会死去。
给你一个整数数组 flowerbed 表示花坛,由若干 0 和 1 组成,其中 0 表示没种植花,1 表示种植了花。另有一个数 n ,能否在不打破种植规则的情况下种入 n 朵花?能则返回 true ,不能则返回 false。
示例 1:
输入:flowerbed = [1,0,0,0,1], n = 1
输出:true
思路实现
class Solution { public boolean canPlaceFlowers(int[] flowerbed, int n) { int res = 0; int begin = -1; for(int index=0; index < flowerbed.length; index++){ if(flowerbed[index] ==1){ if(begin < 0){ res += index/2; }else{ res += (index - begin -2)/2; } begin = index; } } if(begin < 0){ res += (flowerbed.length+1)/2; }else{ res += (flowerbed.length - begin -1)/2; } return res >= n; } }
题目606
根据二叉树创建字符串
你需要采用前序遍历的方式,将一个二叉树转换成一个由括号和整数组成的字符串。
空节点则用一对空括号 "()" 表示。而且你需要省略所有不影响字符串与原始二叉树之间的一对一映射关系的空括号对。
思路实现
class Solution { public String tree2str(TreeNode t) { if(t == null){ return ""; } StringBuilder res = new StringBuilder(); res.append(String.valueOf(t.val)); if(t.left != null){ res.append("("); res.append(tree2str(t.left)); res.append(")"); } if(t.left == null && t.right != null){ res.append("()"); } if(t.right != null){ res.append("("); res.append(tree2str(t.right)); res.append(")"); } return res.toString(); } }
题目609
在系统中查找重复文件
给定一个目录信息列表,包括目录路径,以及该目录中的所有包含内容的文件,您需要找到文件系统中的所有重复文件组的路径。一组重复的文件至少包括二个具有完全相同内容的文件。
输入列表中的单个目录信息字符串的格式如下:
"root/d1/d2/.../dm f1.txt(f1_content) f2.txt(f2_content) ... fn.txt(fn_content)"
这意味着有 n 个文件(f1.txt, f2.txt ... fn.txt 的内容分别是 f1_content, f2_content ... fn_content)在目录 root/d1/d2/.../dm 下。注意:n>=1 且 m>=0。如果 m=0,则表示该目录是根目录。
该输出是重复文件路径组的列表。对于每个组,它包含具有相同内容的文件的所有文件路径。文件路径是具有下列格式的字符串:
"directory_path/file_name.txt"
思路
哈希表
实现
class Solution { public List<List<String>> findDuplicate(String[] paths) { HashMap<String, List<String>> map = new HashMap<>(); for(String path: paths){ String[] values = path.split(" "); for(int index = 1; index<values.length; index++){ String[] file = values[index].split("\\("); file[1] = file[1].replace(")", ""); List<String> value= map.getOrDefault(file[1], new ArrayList < String > ()); value.add(values[0]+"/"+file[0]); map.put(file[1], value); } } List<List<String>> res = new ArrayList<>(); for(List<String> value: map.values()){ if (value.size() >1) res.add(value); } return res; } }
题目611
有效的三角形个数
给定一个包含非负整数的数组,你的任务是统计其中可以组成三角形三条边的三元组个数。
思路
1.暴力法
2.双指针:改进方式是将暴力法中的第二层和第三层循环合成一个,从后往前遍历可以提前结束循环
从最大值开始遍历,index为当前索引,left为0,right为index-1,若满足三角形条件,则left到right-1所有值都可以和right,index组成三角形,可以将right-1进行下一次选择;若不满足条件,则是left太小了,left+1
实现
class Solution { public int triangleNumber(int[] nums) { Arrays.sort(nums); int res = 0; for(int i=0; i< nums.length; i++){ for(int j=i+1; j< nums.length; j++){ for(int k = j+1; k < nums.length; k++){ if(nums[i]+nums[j]>nums[k]){ res +=1; }else{ break; } } } } return res; } } class Solution { public int triangleNumber(int[] nums) { Arrays.sort(nums); int res = 0; int left,right; for(int index= nums.length-1; index >=2; index--){ left = 0; right = index-1; while (left < right){ if(nums[left]+nums[right]>nums[index]){ res += (right - left); right -=1; }else{ left += 1; } } } return res; } }
题目617
合并二叉树
给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。
你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。
思路实现
class Solution { public TreeNode mergeTrees(TreeNode t1, TreeNode t2) { if(t1 == null && t2 == null){ return null; }else if(t1 == null){ return t2; }else if(t2 == null){ return t1; } t1.val += t2.val; t1.left = mergeTrees(t1.left, t2.left); t1.right = mergeTrees(t1.right, t2.right); return t1; } }
题目621
任务调度器
给你一个用字符数组 tasks 表示的 CPU 需要执行的任务列表。其中每个字母表示一种不同种类的任务。任务可以以任意顺序执行,并且每个任务都可以在 1 个单位时间内执行完。在任何一个单位时间,CPU 可以完成一个任务,或者处于待命状态。
然而,两个 相同种类 的任务之间必须有长度为整数 n 的冷却时间,因此至少有连续 n 个单位时间内 CPU 在执行不同的任务,或者在待命状态。
你需要计算完成所有任务所需要的 最短时间 。
示例 1:
输入:tasks = ["A","A","A","B","B","B"], n = 2
输出:8
解释:A -> B -> (待命) -> A -> B -> (待命) -> A -> B
在本示例中,两个相同类型任务之间必须间隔长度为 n = 2 的冷却时间,而执行一个任务只需要一个单位时间,所以中间出现了(待命)状态。
思路
贪心算法:
maxTimes为出现次数最多的那个任务出现的次数。maxCount为出现次数为maxTimes的任务总数。占用的时间为(maxTimes−1)∗(n+1)+maxCount。
如果任务种类很多,在安排时无需冷却时间,只需要在一个任务的两次出现间填充其他任务,然后从左到右从上到下依次执行即可,由于每一个任务占用一个时间单位,
实现
class Solution { public int leastInterval(char[] tasks, int n) { int[] buckets = new int[26]; for(char task: tasks){ buckets[task-'A'] +=1; } int maxCount= 0; int maxExec = 0; for(int count: buckets){ if(count > maxCount){ maxCount = count; maxExec = 1; }else if(count == maxCount){ maxExec += 1; } } return Math.max(tasks.length, (maxCount-1)*(n+1)+maxExec); } }
题目622
设计循环队列
设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。
你的实现应该支持如下操作:
MyCircularQueue(k): 构造器,设置队列长度为 k 。
Front: 从队首获取元素。如果队列为空,返回 -1 。
Rear: 获取队尾元素。如果队列为空,返回 -1 。
enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
isEmpty(): 检查循环队列是否为空。
isFull(): 检查循环队列是否已满。
思路实现
class MyCircularQueue { private int[] queue; private int headIndex; private int count; private int capacity; public MyCircularQueue(int k) { capacity = k; queue = new int [k]; headIndex = 0; count = 0; } public boolean enQueue(int value) { if(isFull()) return false; queue[(headIndex+count)%capacity] = value; count += 1; return true; } public boolean deQueue() { if(isEmpty()) return false; headIndex = (headIndex+1)%capacity; count -= 1; return true; } public int Front() { if(isEmpty()) return -1; return queue[headIndex]; } public int Rear() { if(isEmpty()) return -1; return queue[(headIndex+count-1)%capacity]; } public boolean isEmpty() { if(count == 0) return true; return false; } public boolean isFull() { if(count == capacity) return true; return false; } }
题目623
在二叉树中增加一行
给定一个二叉树,根节点为第1层,深度为 1。在其第 d 层追加一行值为 v 的节点。
添加规则:给定一个深度值 d (正整数),针对深度为 d-1 层的每一非空节点 N,为 N 创建两个值为 v 的左子树和右子树。
将 N 原先的左子树,连接为新节点 v 的左子树;将 N 原先的右子树,连接为新节点 v 的右子树。
如果 d 的值为 1,深度 d - 1 不存在,则创建一个新的根节点 v,原先的整棵树将作为 v 的左子树。
思路实现
class Solution { private int v; private int d; public TreeNode addOneRow(TreeNode root, int v, int d) { if(d == 1){ TreeNode node = new TreeNode(v); node.left = root; return node; } this.v = v; this.d = d; trace(1, root); return root; } private void trace(int height, TreeNode node){ if (height == d-1){ TreeNode tempLeft = node.left; TreeNode tempRight = node.right; TreeNode newLeft = new TreeNode(v); TreeNode newRight = new TreeNode(v); newLeft.left = tempLeft; newRight.right = tempRight; node.left = newLeft; node.right = newRight; return; }else if(height < d-1){ if(node.left != null) trace(height+1, node.left); if(node.right != null) trace(height+1, node.right); } } }
题目628
三个数的最大乘积
给定一个整型数组,在数组中找出由三个数组成的最大乘积,并输出这个乘积。
思路实现
class Solution { public int maximumProduct(int[] nums) { int min1 = Integer.MAX_VALUE, min2 = Integer.MAX_VALUE; int max1 = Integer.MIN_VALUE, max2 = Integer.MIN_VALUE, max3 = Integer.MIN_VALUE; for(int num: nums){ if(num >= max1){ max3 = max2; max2 = max1; max1 = num; }else if(num >= max2){ max3 = max2; max2 = num; }else if(num >= max3){ max3 = num; } if(num <= min1){ min2 = min1; min1 = num; }else if(num <= min2){ min2 = num; } } return Math.max(max1*max2*max3, min1*min2*max1); } }