「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战」。
LeetCode习题集 有些题可能直接略过了,整理一下之前刷leetcode
513. 找树左下角的值
给定一个二叉树,在树的最后一行找到最左边的值。
示例 1:
输入:
2
/ \
1 3
输出: 1
示例 2:
输入:
1
/ \
2 3
/ / \
4 5 6
/
7
输出: 7
注意: 您可以假设树(即给定的根节点)不为 NULL。
PS:
类似于BFS遍历
如果有右节点,先添加右结点,在添加左节点,最后一个结点既是目标节点
如果先添加左结点在添加右结点,最后求的是最后一行最右面的值。
/**
* 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<>();
queue.offer(root);
while(!queue.isEmpty()){
root = queue.poll();
if (root.right != null) queue.offer(root.right);
if (root.left != null) queue.offer(root.left);
}
return root.val;
}
}
514. 自由之路
视频游戏“辐射4”中,任务“通向自由”要求玩家到达名为“Freedom Trail Ring”的金属表盘,并使用表盘拼写特定关键词才能开门。
给定一个字符串 ring,表示刻在外环上的编码;给定另一个字符串 key,表示需要拼写的关键词。您需要算出能够拼写关键词中所有字符的最少步数。
最初,ring 的第一个字符与12:00方向对齐。您需要顺时针或逆时针旋转 ring 以使 key 的一个字符在 12:00 方向对齐,然后按下中心按钮,以此逐个拼写完 key 中的所有字符。
旋转 ring 拼出 key 字符 key[i] 的阶段中:
您可以将 ring 顺时针或逆时针旋转一个位置,计为1步。旋转的最终目的是将字符串 ring 的一个字符与 12:00 方向对齐,并且这个字符必须等于字符 key[i] 。
如果字符 key[i] 已经对齐到12:00方向,您需要按下中心按钮进行拼写,这也将算作 1 步。按完之后,您可以开始拼写 key 的下一个字符(下一阶段), 直至完成所有拼写。
示例:
输入: ring = "godding", key = "gd" 输出: 4 解释: 对于 key 的第一个字符 'g',已经在正确的位置, 我们只需要1步来拼写这个字符。 对于 key 的第二个字符 'd',我们需要逆时针旋转 ring "godding" 2步使它变成 "ddinggo"。 当然, 我们还需要1步进行拼写。 因此最终的输出是 4。 提示:
ring 和 key 的字符串长度取值范围均为 1 至 100; 两个字符串中都只有小写字符,并且均可能存在重复字符; 字符串 key 一定可以由字符串 ring 旋转拼出。
Ps:
DP【i】【j】指的是key第i个字符匹配的轮盘的第j个数字
因为我是两边转,在dp基础上加一个判断正反最小的
当 skey[i] == sring[j] 时
如果是key第一个字符就直接计数,正着转或者反着转
如果不是key第一个字符,就看上一个字符是到哪了,找到上一个字符转到这个字符最小的那个,这里也要考虑正反转
如果是key最后一个字符,就记录一下,看看哪个是最少的
class Solution {
public int findRotateSteps(String ring, String key) {
char[] sring = ring.toCharArray();
char[] skey = key.toCharArray();
int[][] dp = new int[key.length()][ring.length()];
for(int i = 0 ; i < dp.length ; i ++){
Arrays.fill(dp[i], Integer.MAX_VALUE);
}
int n = ring.length();
int count = Integer.MAX_VALUE;
for(int i = 0 ; i < skey.length ; i ++) {
for(int j = 0 ; j < n; j ++){
if(skey[i] == sring[j]){
if(i == 0)
dp[i][j] = Math.min(j, n - j);
else{
for(int k = 0 ; k < n ; k ++){
if(dp[i - 1][k] != Integer.MAX_VALUE){
dp[i][j] = Math.min(dp[i][j], dp[i - 1][k] + Math.min(Math.abs(j - k), n - Math.abs(j - k)));
}
}
}
if(i == skey.length - 1)
count = Math.min(count, dp[i][j]);
}
}
}
return count + skey.length;
}
515. 在每个树行中找最大值
您需要在二叉树的每一行中找到最大的值。
示例:
输入:
1
/ \
3 2
/ \ \
5 3 9
输出: [1, 3, 9]
PS:
遍历树,递归遍历,遍历的同时加上对应的层数
每遍历到一个节点,比较同层的结点,找到最大的那个值,保存最大的值
list的对应的下标当作对应的层数,每个下标对应的值就是当前树对应层的最大值
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<Integer> list = new ArrayList<>();
public List<Integer> largestValues(TreeNode root) {
dfs(root,0);
return list;
}
public void dfs(TreeNode tree,int cen){
if(tree==null) return;
if(cen==list.size()) list.add(tree.val);
else{
if(list.get(cen)<tree.val){
list.remove(cen);
list.add(cen,tree.val);
}
}
dfs(tree.left,cen+1);
dfs(tree.right,cen+1);
}
}
516. 最长回文子序列
给定一个字符串s,找到其中最长的回文子序列。可以假设s的最大长度为1000。
示例 1: 输入:
"bbbab" 输出:
4 一个可能的最长回文子序列为 "bbbb"。
示例 2: 输入:
"cbbd" 输出:
2 一个可能的最长回文子序列为 "bb"。
PS:
动态规划,
第一个就不多说了,dp【i】【j】就是截取后i位,然后挨着截取后i位的第j位
相等就+2,不相等找【i+1】【j】和【i】【j-1】中最大的
第二个,根据第一个我一直是用的我的上一个,因为我是i越来越小
然后直接用两个数组,一个保存上一个,一个记录现在,
然后替换即可
class Solution {
// public int longestPalindromeSubseq(String s) {
// if (s == null || s.length() == 0) {
// return 0;
// }
// int n = s.length();
// int[][] dp = new int[n][n];
// for (int i = n - 1; i >= 0; i--) {
// dp[i][i] = 1;
// for (int j = i + 1; j < n; j++) {
// if (s.charAt(i) == s.charAt(j)) {
// dp[i][j] = dp[i + 1][j - 1] + 2;
// } else {
// dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
// }
// }
// }
// return dp[0][n - 1];
// }
public int longestPalindromeSubseq(String s) {
char[] chars=s.toCharArray();
int length=s.length();
int[] current=new int[length];
int[] pre =new int[length];
for(int i=length-1;i>=0;i--){
current[i]=1;
for(int j=i+1;j<length;j++){
if(chars[i]==chars[j]){
current[j]=pre[j-1]+2;
}else{
current[j]=Math.max(current[j-1],pre[j]);
}
}
int[] tmp=pre;
pre=current;
current=tmp;
}
return pre[length-1];
}
}
517. 超级洗衣机
假设有 n 台超级洗衣机放在同一排上。开始的时候,每台洗衣机内可能有一定量的衣服,也可能是空的。
在每一步操作中,你可以选择任意 m (1 ≤ m ≤ n) 台洗衣机,与此同时将每台洗衣机的一件衣服送到相邻的一台洗衣机。
给定一个非负整数数组代表从左至右每台洗衣机中的衣物数量,请给出能让所有洗衣机中剩下的衣物的数量相等的最少的操作步数。如果不能使每台洗衣机中衣物的数量相等,则返回 -1。
示例 1:
输入: [1,0,5]
输出: 3
解释:
第一步: 1 0 <-- 5 => 1 1 4
第二步: 1 <-- 1 <-- 4 => 2 1 3
第三步: 2 1 <-- 3 => 2 2 2
示例 2:
输入: [0,3,0]
输出: 2
解释:
第一步: 0 <-- 3 0 => 1 2 0
第二步: 1 2 --> 0 => 1 1 1
示例 3:
输入: [0,2,0]
输出: -1
解释: 不可能让所有三个洗衣机同时剩下相同数量的衣物。
提示:
n 的范围是 [1, 10000]。 在每台超级洗衣机中,衣物数量的范围是 [0, 1e5]。
PS:
我移动的最小的次数,无非来源于两种
我当前值和平均值的差
我前面差的和
class Solution {
public int findMinMoves(int[] machines) {
int sum = 0;
for(int num : machines)
sum += num;
if(sum % machines.length != 0)
return -1;
int target = sum / machines.length;
int res = 0, balance = 0;
for(int i = 0 ; i < machines.length; i ++){
balance += machines[i] - target;
res = Math.max(res, Math.max(machines[i] - target, Math.abs(balance)));
}
return res;
}
}
518. 零钱兑换 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 示例 2:
输入: amount = 3, coins = [2] 输出: 0 解释: 只用面额2的硬币不能凑成总金额3。 示例 3:
输入: amount = 10, coins = [10] 输出: 1
注意:
你可以假设:
0 <= amount (总金额) <= 5000 1 <= coin (硬币面额) <= 5000 硬币种类不超过 500 种 结果符合 32 位符号整数
PS:
当前的钱在大于硬币面值得情况下就是我的【j-当前硬币得面值】
把每一种金币都循环一遍
class Solution {
public int change(int amount, int[] coins) {
int dp[] = new int[amount+1];
dp[0] = 1;
for (int coin : coins) {
for (int j = 1; j <= amount; j++) {
if (j >= coin) {
dp[j] = dp[j] + dp[j - coin];
}
}
}
return dp[amount];
}
}
519. 随机翻转矩阵
题中给出一个 n 行 n 列的二维矩阵 (n_rows,n_cols),且所有值被初始化为 0。要求编写一个 flip 函数,均匀随机的将矩阵中的 0 变为 1,并返回该值的位置下标 [row_id,col_id];同样编写一个 reset 函数,将所有的值都重新置为 0。尽量最少调用随机函数 Math.random(),并且优化时间和空间复杂度。
注意:
1.1 <= n_rows, n_cols <= 10000
- 0 <= row.id < n_rows 并且 0 <= col.id < n_cols
3.当矩阵中没有值为 0 时,不可以调用 flip 函数
4.调用 flip 和 reset 函数的次数加起来不会超过 1000 次
示例 1:
输入: ["Solution","flip","flip","flip","flip"] [[2,3],[],[],[],[]] 输出: [null,[0,1],[1,2],[1,0],[1,1]] 示例 2:
输入: ["Solution","flip","flip","reset","flip"] [[1,2],[],[],[],[]] 输出: [null,[0,0],[0,1],null,[0,0]] 输入语法解释:
输入包含两个列表:被调用的子程序和他们的参数。Solution 的构造函数有两个参数,分别为 n_rows 和 n_cols。flip 和 reset 没有参数,参数总会以列表形式给出,哪怕该列表为空
PS: 自己映射一个数组 map保存点的信息,点采用横坐标乘纵坐标的方法存储 ,reset时就重置该点
class Solution {
Map<Integer, Integer> V = new HashMap<>();
int nr, nc, rem;
Random rand = new Random();
public Solution(int n_rows, int n_cols) {
nr = n_rows;
nc = n_cols;
rem = nr * nc;
}
public int[] flip() {
int r = rand.nextInt(rem--);
int x = V.getOrDefault(r, r);
V.put(r, V.getOrDefault(rem, rem));
return new int[]{x / nc, x % nc};
}
public void reset() {
V.clear();
rem = nr * nc;
}
}
/**
* Your Solution object will be instantiated and called as such:
* Solution obj = new Solution(n_rows, n_cols);
* int[] param_1 = obj.flip();
* obj.reset();
*/
520. 检测大写字母
给定一个单词,你需要判断单词的大写使用是否正确。
我们定义,在以下情况时,单词的大写用法是正确的:
全部字母都是大写,比如"USA"。 单词中所有字母都不是大写,比如"leetcode"。 如果单词不只含有一个字母,只有首字母大写, 比如 "Google"。 否则,我们定义这个单词没有正确使用大写字母。
示例 1:
输入: "USA" 输出: True 示例 2:
输入: "FlaG" 输出: False 注意: 输入是由大写和小写拉丁字母组成的非空单词。
class Solution {
public boolean detectCapitalUse(String word) {
int len = word.length();
int cap = 0;
for(int i=0; i<len; i++){
char c = word.charAt(i);
if(c >= 'A' && c <= 'Z') cap++;
}
//判断全是大写和全是小写的情况
if(cap == len || cap == 0) return true;
char f = word.charAt(0);
//判断第一个是大写,其他都是小写的情况
if(cap == 1 && (f >= 'A') && (f <= 'Z')) return true;
return false;
}
}