「这是我参与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);
}
}