leetcode刷题 495~
题目495题
提莫攻击
在《英雄联盟》的世界中,有一个叫 “提莫” 的英雄,他的攻击可以让敌方英雄艾希(编者注:寒冰射手)进入中毒状态。现在,给出提莫对艾希的攻击时间序列和提莫攻击的中毒持续时间,你需要输出艾希的中毒状态总时长。
你可以认为提莫在给定的时间点进行攻击,并立即使艾希处于中毒状态。
示例1:
输入: [1,4], 2
输出: 4
原因: 第 1 秒初,提莫开始对艾希进行攻击并使其立即中毒。中毒状态会维持 2 秒钟,直到第 2 秒末结束。
第 4 秒初,提莫再次攻击艾希,使得艾希获得另外 2 秒中毒时间。
所以最终输出 4 秒。
思路
双指针
实现
class Solution { public int findPoisonedDuration(int[] timeSeries, int duration) { int result = 0; int left = 0; int right = 0; for (int time: timeSeries){ if (time >= right){ result += duration; left = time; right = left + duration; } else{ left = time; result = result + duration + left - right; right = left + duration; } } return result; } }
题目496题
下一个更大的元素I
给定两个 没有重复元素 的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。找到 nums1 中每个元素在 nums2 中的下一个比其大的值。
nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位置的右边的第一个比 x 大的元素。如果不存在,对应位置输出 -1 。
示例 1:
输入: nums1 = [4,1,2], nums2 = [1,3,4,2].
输出: [-1,3,-1]
思路
单调栈:首先遍历nums2,利用哈希表记录每个元素下一个更大值。然后遍历nums1获取结果
实现
class Solution { public int[] nextGreaterElement(int[] nums1, int[] nums2) { Stack < Integer > stack = new Stack<>(); HashMap < Integer, Integer > map = new HashMap < > (); for(int num: nums2){ while(! stack.empty() && stack.peek()<num){ map.put(stack.pop(), num); } stack.push(num); } while(!stack.empty()){ map.put(stack.pop(),-1); } int[] result = new int[nums1.length]; for(int i = 0; i < nums1.length; i++){ result[i] = map.get(nums1[i]); } return result; } }
题目497题
非重叠矩阵中的随机点
给定一个非重叠轴对齐矩形的列表 rects
,写一个函数 pick
随机均匀地选取矩形覆盖的空间中的整数点。
示例 1:
输入:
["Solution","pick","pick","pick"]
[[[[1,1,5,5]]],[],[],[]]
输出:
[null,[4,1],[4,1],[3,3]]
思路
首先计算所有整数点的总和,然后采用蓄水池抽样,或者二分查找,找到随机点。
实现
import java.util.Random; class Solution { private int[][] rects; private int rectsNum = 0; private List<Integer> rectArray = new ArrayList<>(); public Solution(int[][] rects) { this.rects = rects; for (int[] rect: rects){ rectsNum += (rect[2] - rect[0] + 1)*(rect[3] - rect[1] + 1); rectArray.add(rectsNum); } } public int[] pick() { Random random =new Random(); int randomIndex = random.nextInt(rectsNum); int left = 0; int right = rects.length-1; while(left != right){ int mid = left + (right-left)/2; if(randomIndex >= rectArray.get(mid)){ left = mid +1; } else{ right = mid; } } int rectsIndex = left; int[] rect = rects[rectsIndex]; int length = rect[2] - rect[0] + 1; int high = rect[3] - rect[1] + 1; int lengthIndex = random.nextInt(length); int highIndex = random.nextInt(high); int[] result = new int[2]; result[0] = rect[0] + lengthIndex; result[1] = rect[1] + highIndex; return result; } } /** * Your Solution object will be instantiated and called as such: * Solution obj = new Solution(rects); * int[] param_1 = obj.pick(); */
题目498题
对角线遍历
给定一个含有 M x N 个元素的矩阵(M 行,N 列),请以对角线遍历的顺序返回这个矩阵中的所有元素,对角线遍历如下图所示。
思路实现
class Solution { public int[] findDiagonalOrder(int[][] matrix) { if (matrix == null || matrix.length == 0) { return new int[]{}; } int M = matrix.length, N = matrix[0].length; int[] result = new int[M*N]; int row = 0, col = 0; for(int index = 0; index < M*N; index++){ result[index] = matrix[row][col]; int level = row+col; if(level%2==0){ if(col == N-1){ row += 1; } else if(row == 0){ col += 1; } else{ row -= 1; col += 1; } } else{ if(row == M-1){ col += 1; } else if(col == 0){ row += 1; } else{ col -= 1; row += 1; } } } return result; } }
题目500题
键盘行
给定一个单词列表,只返回可以使用在键盘同一行的字母打印出来的单词。键盘如下图所示。
思路实现
class Solution { public String[] findWords(String[] words) { String[] keyboard = new String[]{"QWERTYUIOP", "ASDFGHJKL", "ZXCVBNM"}; HashMap<Character,Integer> lines = new HashMap<>(); for(int index = 0; index <3; index++){ for(char c:keyboard[index].toCharArray()){ c = Character.toUpperCase(c); lines.put(c,index); } } String[] result = new String[words.length]; int count = 0; for(String word: words){ Integer line = -1; boolean temp = true; for(char c:word.toCharArray()){ c = Character.toUpperCase(c); Integer next = lines.get(c); if (line != -1 && next != line){ temp = false; break; } line = next; } if(temp == true){ result[count] = word; count += 1; } } return Arrays.copyOf(result, count); } }
题目501题
二叉搜索树中的重数
给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素)。
思路
中序遍历
实现
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { private List<Integer> answer = new ArrayList<Integer>(); private int cur = 0, count = 0, MaxCount = 0; public int[] findMode(TreeNode root) { dfs(root); int[] result = answer.stream().mapToInt(k->k).toArray(); return result; } private void dfs(TreeNode node){ if (node == null){ return; } dfs(node.left); check(node.val); dfs(node.right); } private void check(int val){ if (val == cur){ count += 1; } else{ count = 1; cur = val; } if(count == MaxCount){ answer.add(val); } else if (count > MaxCount){ MaxCount = count; answer.clear(); answer.add(val); } } }
题目503题
下一个更大元素II
给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。
示例 1:
输入: [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数;
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。
思路
与496题相同思路相同,使用栈来解决问题。
首先第一次遍历,得到部分下一个元素更大的结果,此时,栈中保存着一个单调递减的元素索引,其实第一个元素是整个数组的最大元素。遍历0到最大索引,将得到栈中值的结果。
实现
class Solution { public int[] nextGreaterElements(int[] nums) { if(nums.length == 0) { return new int[]{}; } Stack < Integer > stack = new Stack<>(); int[] result = new int[nums.length]; for (int index=0; index<nums.length; index++) { while(!stack.empty() && nums[stack.peek()] < nums[index]) { int tempIndex = stack.pop(); result[tempIndex] = nums[index]; } stack.push(index); } int maxIndex = stack.get(0); int index = 0; while(!stack.empty()) { int numIndex = stack.pop(); while(index <= maxIndex && nums[numIndex] >= nums[index]) { index += 1; } result[numIndex] = nums[numIndex] != nums[maxIndex] ? nums[index]:-1; } return result; } }
题目504题
7进制数
给定一个整数,将其转化为7进制,并以字符串形式输出。
思路实现
class Solution { public String convertToBase7(int num) { char[] digits = new char[]{'0', '1', '2', '3', '4', '5', '6'}; char[] result = new char[33]; boolean sign = (num < 0); if(sign){ num = -num; } int index = 32; while(num>=7) { result[index] = digits[num%7]; num = num/7 ; index -= 1; } result[index] = digits[num]; if(sign) { index -= 1; result[index] = '-'; } return new String(result,index,33-index); } }
题目506题
相对名次
给出 N 名运动员的成绩,找出他们的相对名次并授予前三名对应的奖牌。前三名运动员将会被分别授予 “金牌”,“银牌” 和“ 铜牌”("Gold Medal", "Silver Medal", "Bronze Medal")。
思路实现
class Solution { public String[] findRelativeRanks(int[] nums) { String[] res = new String[nums.length]; HashMap<Integer,Integer> map = new HashMap<Integer,Integer>(); for (int i = 0; i < nums.length; i++) { map.put(nums[i], i); } Arrays.sort(nums); int cur = 0; for (int i = nums.length-1; i >= 0; i--) { if(cur == 0) { res[map.get(nums[i])] = "Gold Medal"; } else if (cur == 1) { res[map.get(nums[i])] = "Silver Medal"; } else if (cur == 2) { res[map.get(nums[i])] = "Bronze Medal"; } else { res[map.get(nums[i])] = Integer.toString(cur+1); } cur +=1; } return res; } }
题目508题
出现次数最多的子树元素和
给你一个二叉树的根结点,请你找出出现次数最多的子树元素和。一个结点的「子树元素和」定义为以该结点为根的二叉树上所有结点的元素之和(包括结点本身)。
你需要返回出现次数最多的子树元素和。如果有多个元素出现的次数相同,返回所有出现次数最多的子树元素和(不限顺序)。
思路
哈希表
实现
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { private HashMap<Integer,Integer> total = new HashMap<Integer,Integer>(); private int maxCount = 0; public int[] findFrequentTreeSum(TreeNode root) { dfs(root); List<Integer> list = new ArrayList<>(); for (Integer key: total.keySet()) { if (total.get(key) == maxCount) { list.add((int)key); } } int[] res = new int[list.size()]; for(int i = 0; i < list.size();i++) { res[i] = list.get(i); } return res; } private int dfs(TreeNode node) { if(node == null) { return 0; } int cur = node.val + dfs(node.left) + dfs(node.right); total.put(cur, total.getOrDefault(cur,0)+1); maxCount = Math.max(maxCount,total.get(cur)); return cur; } }
题目509题
斐波那契数
斐波那契数,通常用 F(n) 表示,形成的序列称为斐波那契数列。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:
F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
给定 N,计算 F(N)。
思路实现
class Solution { private int[] fn = new int[31]; public int fib(int N) { buildfn(); return fn[N]; } private void buildfn() { fn[0] = 0; fn[1] = 1; for(int index = 2; index < 31; index++) { fn[index] = fn[index-1] + fn[index-2]; } } }
题目513题
找树左下角的值
给定一个二叉树,在树的最后一行找到最左边的值。
思路实现
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public int findBottomLeftValue(TreeNode root) { Queue<TreeNode> queue = new LinkedList<TreeNode>(); if(root == null) { return 0; } queue.offer(root); TreeNode cur = new TreeNode(0); while(queue.size() > 0) { cur = queue.poll(); if(cur.right != null) { queue.offer(cur.right); } if(cur.left != null) { queue.offer(cur.left); } } return cur.val; } }
题目515题
在每个树行中找最大值
需要在二叉树的每一行中找到最大的值。
思路实现
class Solution { public List<Integer> largestValues(TreeNode root) { List<Integer> res = new ArrayList<Integer>(); if(root == null) { return res; } Queue<TreeNode> queue = new LinkedList<TreeNode>(); queue.offer(root); while(!queue.isEmpty()) { int max = Integer.MIN_VALUE; int curSize = queue.size(); for(int i =0; i < curSize; i++) { TreeNode node = queue.poll(); max = Math.max(max,node.val); if(node.left != null) { queue.offer(node.left); } if(node.right != null) { queue.offer(node.right); } } res.add(max); } return res; } }
题目516题
最长回文子序列
给定一个字符串 s
,找到其中最长的回文子序列,并返回该序列的长度。可以假设 s
的最大长度为 1000
。
思路
动态规划
dp[i][j]
表示 s
的第 i
个字符到第 j
个字符组成的子串中,最长的回文序列长度是多少。
如果 s 的第 i 个字符和第 j 个字符相同的话,dp[i][j] = dp[i + 1][j - 1] + 2,表明第 i
个字符到第 j
个字符组成的子串回文长度等于第 i+1
个字符到第 j-1 个字符组成的子串回文长度
当序列为 b aa b 时, i = 0, j = 3,则 dp[0][3] = dp[1][2] + 2 = 4
当序列为 b a b 时,i = 0, j = 2,则 dp[0][2] = dp[1][1] + 2 = 3
当序列为 b b 时, i = 0, j = 1,则 dp[0][1] = dp[1][0] = 0 + 2 = 2 (dp[1][0] 默认值为 0)
如果 s 的第 i 个字符和第 j 个字符不同的话,dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]),表明第 i
个字符到第 j
个字符组成的子串回文长度等于第 i+1
个字符到第 j 个字符组成的子串回文长度和者第 i
个字符到第 j-1
个字符组成的子串回文长度两者最大值
假如序列为 d c b c c(index:0-4),s[0] != s[4] ,则 dp[0][4] = Math.max(dp[0][3],dp[1,4]) = Math.max(2,3) = 3
实现
class Solution { public int longestPalindromeSubseq(String s) { char[] string = s.toCharArray(); int sLen = s.length(); int[][] dp = new int[sLen][sLen]; for(int i = sLen - 1; i >=0; i--) { dp[i][i] =1; for(int j = i+1; j < sLen; j++) { if(string[j] == string[i]) { dp[i][j] = dp[i+1][j-1] +2; } else { dp[i][j] = Math.max(dp[i][j-1],dp[i+1][j]); } } } return dp[0][sLen-1]; } }
题目495题
零钱兑换II
给定不同面额的硬币和一个总金额。写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。
示例 1:
输入: amount = 5, coins = [1, 2, 5]
输出: 4
解释: 有四种方式可以凑成总金额:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1
思路
动态规划
实现
class Solution { public int change(int amount, int[] coins) { int coinNum = coins.length; int[] dp = new int[amount+1]; dp[0] = 1; for(int coin:coins) { for(int sum = coin ;sum <= amount; sum++) { dp[sum] += dp[sum-coin]; } } return dp[amount]; } }