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];
    }
}
posted @ 2020-12-07 18:23  maoguai  阅读(70)  评论(0编辑  收藏  举报