Java实现LeetCode 题号:521 - 530

155 阅读4分钟

「这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战」。

LeetCode习题集 有些题可能直接略过了,整理一下之前刷leetcode

521. 最长特殊序列 Ⅰ

给定两个字符串,你需要从这两个字符串中找出最长的特殊序列。最长特殊序列定义如下:该序列为某字符串独有的最长子序列(即不能是其他字符串的子序列)。

子序列可以通过删去字符串中的某些字符实现,但不能改变剩余字符的相对顺序。空序列为所有字符串的子序列,任何字符串为其自身的子序列。

输入为两个字符串,输出最长特殊序列的长度。如果不存在,则返回 -1。

示例 :

输入: "aba", "cdc" 输出: 3 解析: 最长特殊序列可为 "aba" (或 "cdc") 说明:

两个字符串长度均小于100。 字符串中的字符仅含有 'a'~'z'。

PS:

既然是饶舌出题人,那我也给你弄个饶舌解答(尽弄些花里胡哨的说明)

class Solution {
    public int findLUSlength(String a, String b) {
        return a.equals(b) ? -1 : a.length() > b.length() ? a.length() : b.length();
    }
}

522. 最长特殊序列 II

给定字符串列表,你需要从它们中找出最长的特殊序列。最长特殊序列定义如下:该序列为某字符串独有的最长子序列(即不能是其他字符串的子序列)。

子序列可以通过删去字符串中的某些字符实现,但不能改变剩余字符的相对顺序。空序列为所有字符串的子序列,任何字符串为其自身的子序列。

输入将是一个字符串列表,输出是最长特殊序列的长度。如果最长特殊序列不存在,返回 -1 。

示例:

输入: "aba", "cdc", "eae" 输出: 3

提示:

所有给定的字符串长度不会超过 10 。 给定字符串列表的长度将在 [2, 50 ] 之间。

PS;
	查找最长的非子序列问题
        双层循环 i,j 判断是否为子字符串
            如果字符串 i 为字符串 j 的子字符串,当前字符串i被废弃,不能加入计算
            如果i循环完所有j,都不是子字符串,当前字符串可以当作一个结果,记录下最长的字符串长度
        记录最长字符串长度ret  ,ret初始为 -1
class Solution {
    public int findLUSlength(String[] strs) {
        int ret = -1;
        if (strs == null || strs.length == 0) {
            return ret;
        }
        int len = strs.length;
        for (int i = 0; i < len; i++) {
            boolean isSubsequence = false;
            for (int j = 0; j < len; j++) {
                if (i != j && isSubsequence(strs[i], strs[j])) {
                    isSubsequence = true;
                    break;
                }
            }
            if (!isSubsequence) {
                ret = Math.max(ret, strs[i].length());
            }
        }

        return ret;
    }

    public boolean isSubsequence(String x, String y) {
        int j = 0;
        for (int i = 0; i < y.length() && j < x.length(); i++)
            if (x.charAt(j) == y.charAt(i))
                j++;
        return j == x.length();
    }
}

523. 连续的子数组和

给定一个包含非负数的数组和一个目标整数 k,编写一个函数来判断该数组是否含有连续的子数组,其大小至少为 2,总和为 k 的倍数,即总和为 n*k,其中 n 也是一个整数。

示例 1:

输入: [23,2,4,6,7], k = 6 输出: True 解释: [2,4] 是一个大小为 2 的子数组,并且和为 6。 示例 2:

输入: [23,2,6,4,7], k = 6 输出: True 解释: [23,2,6,4,7]是大小为 5 的子数组,并且和为 42。 说明:

数组的长度不会超过10,000。 你可以认为所有数字总和在 32 位有符号整数范围内。

PS:
	当求是他的倍数的时候根据余数求
            用前缀和取余操作
                当i j前缀和相同的时候,证明i 到 j 这段和对k取余是0  也就是k的倍数,
                也要满足两个下标的的差大于1
                
                如果不是前缀和相同,就把新结点的前缀和放入map存起来
        测试用例0 0是个烦人的点
class Solution {
       public boolean checkSubarraySum(int[] nums, int k) {
        if(nums.length < 2) return false;
        for(int i = 0; i < nums.length-1; ++i) 
            if(nums[i] == 0 && nums[i+1] == 0) return true;
        if(k == 0) return false;
        if(k < 0) k = -k;
        
        Map<Integer, Integer> map = new HashMap<>();
        map.put(0, -1);
        int sum = 0;
        for(int i = 0; i < nums.length; ++i) {
            sum += nums[i];
            int mod = sum % k;
            if(map.containsKey(mod)) {
                if(i-map.get(mod) > 1)
                    return true;
            }
            else // 不存在再更新
                map.put(mod, i);
        }
        return false;
    }
}

524. 通过删除字母匹配到字典里最长单词

给定一个字符串和一个字符串字典,找到字典里面最长的字符串,该字符串可以通过删除给定字符串的某些字符来得到。如果答案不止一个,返回长度最长且字典顺序最小的字符串。如果答案不存在,则返回空字符串。

示例 1:

输入: s = "abpcplea", d = ["ale","apple","monkey","plea"]

输出: "apple" 示例 2:

输入: s = "abpcplea", d = ["a","b","c"]

输出: "a" 说明:

所有输入的字符串只包含小写字母。 字典的大小不会超过 1000。 所有输入的字符串长度不会超过 1000。

PS:
    先把字典的字符串排个序,这样如果匹配到相同长度肯定是字典序最小的
        后面每次匹配的时候,判断长度是不是比上一个符合的字符串长度长,如果长度不长的话,就略过
    用双指针的方法判断是否为子字符串
    
class Solution {
      public String findLongestWord(String s, List<String> d) {

        Collections.sort(d);
        String res = "";
        for(String word:d){
            if(check(s,word)&&word.length()>res.length()){
                res = word;
            }
        }
        
        return res;
    }
    
    /*利用双指针法判断子串*/
    public boolean check(String s,String p){
        char[] ss = s.toCharArray();
        char[] pp = p.toCharArray();
        int i=0,j=0;
        while(i<ss.length&&j<pp.length){
            if(pp[j]==ss[i])
                j++;
            i++;
        }
        return j==pp.length;
    }
}

525. 连续数组

给定一个二进制数组, 找到含有相同数量的 0 和 1 的最长连续子数组(的长度)。

示例 1:

输入: [0,1] 输出: 2 说明: [0, 1] 是具有相同数量0和1的最长连续子数组。 示例 2:

输入: [0,1,0] 输出: 2 说明: [0, 1] (或 [1, 0]) 是具有相同数量0和1的最长连续子数组。

注意: 给定的二进制数组的长度不会超过50000。

PS:
	饶舌题目
	把0换成-1,相加,看为0的时候,最大长度,
	假如我这次为1,以后的和中又出现了1,那么我这一段是1和0的数量相等
class Solution {
   public int findMaxLength(int[] nums) {
        int res = 0, sum = 0;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == 0) {
                nums[i] = -1;
            }
        }
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            sum += nums[i];
            if (sum == 0 && i > res) {
                res = i + 1;
            }
            if (map.containsKey(sum)) {
                res = Math.max(i - map.get(sum), res);
            } else {
                map.put(sum, i);
            }
        }
        return res;
    }
}

526. 优美的排列

假设有从 1 到 N 的 N 个整数,如果从这 N 个数字中成功构造出一个数组,使得数组的第 i 位 (1 <= i <= N) 满足如下两个条件中的一个,我们就称这个数组为一个优美的排列。条件:

第 i 位的数字能被 i 整除 i 能被第 i 位上的数字整除 现在给定一个整数 N,请问可以构造多少个优美的排列?

示例1:

输入: 2 输出: 2 解释:

第 1 个优美的排列是 [1, 2]: 第 1 个位置(i=1)上的数字是1,1能被 i(i=1)整除 第 2 个位置(i=2)上的数字是2,2能被 i(i=2)整除

第 2 个优美的排列是 [2, 1]: 第 1 个位置(i=1)上的数字是2,2能被 i(i=1)整除 第 2 个位置(i=2)上的数字是1,i(i=2)能被 1 整除 说明:

N 是一个正整数,并且不会超过15。

PS:
    经典DFS,初始时,把1到N个数字全部放入数组中
    进行全排列,排列的时候如果符合条件就放进去,否则就循环下一个
    如果全排列后符合条件,就记一次
class Solution {
    
    private int count = 0;
    private void swap(int[] nums, int i, int j) {
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }
    private void helper(int[] nums, int start) {
        if (start == 0) {
            count++;
            return;
        }
        for (int i = start; i > 0; i--) {
            swap(nums, start, i);
            if (nums[start] % start == 0 || start % nums[start] == 0) helper(nums, start-1);
            swap(nums,i, start);
        }
    }
    public int countArrangement(int N) {
        if (N == 0) return 0;
        int[] nums = new int[N+1];
        for (int i = 0; i <= N; i++) nums[i] = i;
        helper(nums, N);
        return count;
    }
}

528. 按权重随机选择

给定一个正整数数组 w ,其中 w[i] 代表位置 i 的权重,请写一个函数 pickIndex ,它可以随机地获取位置 i,选取位置 i 的概率与 w[i] 成正比。

说明:

1 <= w.length <= 10000 1 <= w[i] <= 10^5 pickIndex 将被调用不超过 10000 次 示例1:

输入: ["Solution","pickIndex"] [[[1]],[]] 输出: [null,0] 示例2:

输入: ["Solution","pickIndex","pickIndex","pickIndex","pickIndex","pickIndex"] [[[1,3]],[],[],[],[],[]] 输出: [null,0,1,1,1,0] 输入语法说明:

输入是两个列表:调用成员函数名和调用的参数。Solution 的构造函数有一个参数,即数组 w。pickIndex 没有参数。输入参数是一个列表,即使参数为空,也会输入一个 [] 空列表。

PS:
	偷个懒
class Solution {

     int sum=0;
    private TreeMap<int[], Integer> range = new TreeMap<>(new Comparator<int[]>() {
        @Override
        public int compare(int[] o1, int[] o2) {
            // 区间内
            if (o1[0] >= o2[0] && o1[1] < o2[1]) {
                return 0;
            // 小于,左区间
            } else if (o1[1] <= o2[0]) {
                return -1;

            // 大于
            } else {
                return 1;
            }
        }
    });

    public Solution(int[] w) {
         int start;
        for(int i=0;i<w.length;i++) {
            start = sum;
            sum += w[i];
            range.put(new int[]{start, sum}, i);
        }
    }
    
    public int pickIndex() {
        int index = (int)(Math.random() * sum);
        if (range.get(new int[]{index, index}) == null) {
            return 0;
        }else{
            return range.get(new int[]{index, index});
        }
    }
}

/**
 * Your Solution object will be instantiated and called as such:
 * Solution obj = new Solution(w);
 * int param_1 = obj.pickIndex();
 */

529. 扫雷游戏

让我们一起来玩扫雷游戏!

给定一个代表游戏板的二维字符矩阵。 'M' 代表一个未挖出的地雷,'E' 代表一个未挖出的空方块,'B' 代表没有相邻(上,下,左,右,和所有4个对角线)地雷的已挖出的空白方块,数字('1' 到 '8')表示有多少地雷与这块已挖出的方块相邻,'X' 则表示一个已挖出的地雷。

现在给出在所有未挖出的方块中('M'或者'E')的下一个点击位置(行和列索引),根据以下规则,返回相应位置被点击后对应的面板:

如果一个地雷('M')被挖出,游戏就结束了- 把它改为 'X'。 如果一个没有相邻地雷的空方块('E')被挖出,修改它为('B'),并且所有和其相邻的方块都应该被递归地揭露。 如果一个至少与一个地雷相邻的空方块('E')被挖出,修改它为数字('1'到'8'),表示相邻地雷的数量。 如果在此次点击中,若无更多方块可被揭露,则返回面板。

示例 1:

输入:

[['E', 'E', 'E', 'E', 'E'], ['E', 'E', 'M', 'E', 'E'], ['E', 'E', 'E', 'E', 'E'], ['E', 'E', 'E', 'E', 'E']]

Click : [3,0]

输出:

[['B', '1', 'E', '1', 'B'], ['B', '1', 'M', '1', 'B'], ['B', '1', '1', '1', 'B'], ['B', 'B', 'B', 'B', 'B']]

解释:

在这里插入图片描述 示例 2:

输入:

[['B', '1', 'E', '1', 'B'], ['B', '1', 'M', '1', 'B'], ['B', '1', '1', '1', 'B'], ['B', 'B', 'B', 'B', 'B']]

Click : [1,2]

输出:

[['B', '1', 'E', '1', 'B'], ['B', '1', 'X', '1', 'B'], ['B', '1', '1', '1', 'B'], ['B', 'B', 'B', 'B', 'B']]

解释: 在这里插入图片描述

注意:

输入矩阵的宽和高的范围为 [1,50]。 点击的位置只能是未被挖出的方块 ('M' 或者 'E'),这也意味着面板至少包含一个可点击的方块。 输入面板不会是游戏结束的状态(即有地雷已被挖出)。 简单起见,未提及的规则在这个问题中可被忽略。例如,当游戏结束时你不需要挖出所有地雷,考虑所有你可能赢得游戏或标记方块的情况。

PS:
	其他情况都好说,主要是空白格的时候,你需要继续去递归,其他情况都是发现地雷或者什么的时候直接返回就可以了

class Solution {
    static public char[][] updateBoard(char[][] board, int[] click) {
       
   	return visit(board,click[0],click[1]);	
   }
	
  static public char[][] visit(char[][] board, int x,int y){
	   if(board[x][y] == 'M') {
		   board[x][y] = 'X';
		   return board;
	   }
   	int count = 0;
       for(int i =x-1;i<=x+1;i++)
          for(int j =y-1; j<= y+1;j++){
        	  if(i>=0 && i < board.length && j>=0 && j<board[0].length)
              if(board[i][j] == 'M')
                   count++;
           }
   	if(count != 0 ) {
   		board[x][y] = (char)(count+'0');
   	}
   	else {
   		board[x][y] = 'B';
   	    for(int i =x-1;i<=x+1;i++)
               for(int j =y-1; j<= y+1;j++){
            	   if(i>=0 && i < board.length && j>=0 && j<board[0].length)
                   if(board[i][j] == 'E')
                       visit(board,i,j);
               }

   	}
   	
   	return board;
   }
}

530. 二叉搜索树的最小绝对差

给你一棵所有节点为非负值的二叉搜索树,请你计算树中任意两节点的差的绝对值的最小值。

示例:

输入:

   1
    \
     3
    /
   2

输出: 1

解释: 最小绝对差为 1,其中 2 和 1 的差的绝对值为 1(或者 2 和 3)。

PS:
   递归遍历
           递归过程中,计算最小差的绝对值
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    private int result = Integer.MAX_VALUE; private TreeNode preNode = null;
    public int getMinimumDifference(TreeNode root) {
    
    getMin(root);
    return result;
}

private void getMin(TreeNode root){
    if(root == null){
        return;
    }
    getMin(root.left);
    if(preNode != null)
    {
        result = Math.min(Math.abs(root.val - preNode.val), result);
    }
    preNode = root;
    getMin(root.right);
}
}