输入:n = 3
输出:4
说明: 有四种走法
示例2:
输入:n = 5
输出:13
提示:
n范围在[1, 1000000]之间
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/three-steps-problem-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
知识点动态规划,跟青蛙跳台类似,坑点: 因为这能条三个台阶,所以我们的动态方程中,有三项d[i-1] + d[i-2] + d[i-3],前两项相加的时候,会存在溢出的情况,因此此时前两项也需要进行取模1000000007操作。
class Solution {
public int waysToStep(int n) {
if(n <= 2) return n;
if (n == 3) return 4;
int[] d = new int[n + 1];
d[1] = 1;
d[2] = 2;
d[3] = 4;
for (int i = 4; i <= n; i++){
d[i] = (d[i-1] + d[i-2]) % 1000000007 +d[i-3];
d[i] %= 1000000007;
}
return d[n];
}
}
Q8.3 魔术索引
魔术索引。 在数组A[0…n-1]中,有所谓的魔术索引,满足条件A[i] = i。给定一个有序整数数组,编写一种方法找出魔术索引,若有的话,在数组A中找出一个魔术索引,如果没有,则返回-1。若有多个魔术索引,返回索引值最小的一个。
示例1:
输入:nums = [0, 2, 3, 4, 5]
输出:0
说明: 0下标的元素为0
示例2:
输入:nums = [1, 1, 1]
输出:1
说明:
nums长度在[1, 1000000]之间
此题为原书中的 Follow-up,即数组中可能包含重复元素的版本
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/magic-index-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
二分法,如果找到中点满足,还需在左半部分继续找
中点不满足,两侧查找
当找到了一个idx以后,区间的端点需要小于idx,才继续找
class Solution {
public int findMagicIndex(int[] nums) {
for(int i=0;i<nums.length;i=Math.max(i+1,nums[i])){
if(nums[i]==i)
return i;
}
return -1;
}
}
Q8.4 幂集
幂集。编写一种方法,返回某集合的所有子集。集合中不包含重复的元素。
说明:解集不能包含重复的子集。
示例:
输入: nums = [1,2,3]
输出:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/power-set-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
class Solution {
public List<List> subsets(int[] nums) {
List list = new LinkedList<>();
List<List> res = new ArrayList<>();
backtrack(nums, 0, list, res);
return res;
}
private void backtrack(int[] nums, int cur, List list, List<List> res) {
res.add(new ArrayList<>(list));
for (int i = cur; i < nums.length; ++i) {
list.add(nums[i]);
backtrack(nums, i + 1, list, res);
list.remove(list.size() - 1);
}
}
}
Q8.5 递归乘法
递归乘法。 写一个递归函数,不使用 * 运算符, 实现两个正整数的相乘。可以使用加号、减号、位移,但要吝啬一些。
示例1:
输入:A = 1, B = 10
输出:10
示例2:
输入:A = 3, B = 4
输出:12
提示:
保证乘法范围不会溢出
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/recursive-mulitply-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
右移1位 == 除以2
左移1位 == 乘以2
class Solution {
public:
int multiply(int A, int B) {
if(A < B)
A=B=A^=B;//swap大的在前,少递归几次
if(B==1)
return A;
if((B&1)==0)//B是偶数
return multiply(A,B>>1)<<1;
else
return A + (multiply(A,B>>1)<<1);
}
};
Q8.6 汉诺塔问题
在经典汉诺塔问题中,有 3 根柱子及 N 个不同大小的穿孔圆盘,盘子可以滑入任意一根柱子。一开始,所有盘子自上而下按升序依次套在第一根柱子上(即每一个盘子只能放在更大的盘子上面)。移动圆盘时受到以下限制:
(1) 每次只能移动一个盘子;
(2) 盘子只能从柱子顶端滑出移到下一根柱子;
(3) 盘子只能叠在比它大的盘子上。
请编写程序,用栈将所有盘子从第一根柱子移到最后一根柱子。
你需要原地修改栈。
示例1:
输入:A = [2, 1, 0], B = [], C = []
输出:C = [2, 1, 0]
示例2:
输入:A = [1, 0], B = [], C = []
输出:C = [1, 0]
提示:
A中盘子的数目不大于14个。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/hanota-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
class Solution {
public void hanota(List A, List B, List C) {
move(A.size(), A, B, C);
}
void move(int n, List A, List B, List C) {
if (n == 1) {
C.add(A.remove(A.size() - 1));
} else {
B.add(A.remove(A.size() - 1));
move(n - 1, A, B, C); // 一处递归即可
C.add(B.remove(B.size() - 1));
}
}
}
Q8.7 无重复字符串的排列组合
无重复字符串的排列组合。编写一种方法,计算某字符串的所有排列组合,字符串每个字符均不相同。
示例1:
输入:S = “qwe”
输出:[“qwe”, “qew”, “wqe”, “weq”, “ewq”, “eqw”]
示例2:
输入:S = “ab”
输出:[“ab”, “ba”]
提示:
字符都是英文字母。
字符串长度在[1, 9]之间。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/permutation-i-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
回溯模板题
class Solution {
private boolean[] used;
/**
如果字符串有重复字母,最简单的去重是使用Set,也可以排序后下标剪枝(相对比较难)
重复字母的全排列可去做《全排列》系列题目。这道题好像和全排列I差不多。
接着要做的就是回溯模板啦,选了的跳过,每次选或不选即可爆搜到所有解。
*/
private List res;
private int len;
public String[] permutation(String S) {
len = S.length();
used = new boolean[len];
res = new ArrayList<>();
dfs(S, new StringBuilder(), 0);
return res.toArray(new String[0]);
}
private void dfs(String s, StringBuilder sb, int cnt) {
// end —— 当sb长度与s长度一致时结束,存储答案
if (cnt == len) {
res.add(sb.toString());
return;
}
// 回溯模板
for (int i = 0; i < len; i++) {
if (!used[i]) {
used[i] = true;
sb.append(s.charAt(i));
dfs(s, sb, cnt + 1);
used[i] = false;
sb.deleteCharAt(cnt);
}
}
}
}
Q8.8 有重复字符串的排列组合
有重复字符串的排列组合。编写一种方法,计算某字符串的所有排列组合。
示例1:
输入:S = “qqe”
输出:[“eqq”,“qeq”,“qqe”]
示例2:
输入:S = “ab”
输出:[“ab”, “ba”]
提示:
字符都是英文字母。
字符串长度在[1, 9]之间。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/permutation-ii-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
这个就是基本的dfs, 不过要注意去重,如果单纯用set则复杂度过高,这里可以直接写规则来过滤,下面简单说一下两种过滤方式,假设数据是aab(这里注意要给字符数组先排序再dfs)
1.arr[i] == arr[i - 1] && book[i - 1]: 该种情况是优先取右,举个简单例子,第一个我们从左到右是a,a,b,这种情况是不可取的,因为当到第二个a时候,第一个a已经用过了,正相反,当我们从第二个a开始的时候,取第一个字符也就是arr[0]=a还没用过,符合条件,故两个a,a,b只会存下来1个。
2.arr[i] == arr[i - 1] && !book[i - 1]: 这个跟第一种过滤方式刚好相反,不过多解释。
还有一种方法可以免去去重步骤,就是可以把字符装桶,然后对桶dfs,只要这个字符还没用完就继续递归下去,有兴趣的可以实现一下。
public String[] permutation(String S) {
List list = new ArrayList<>();
char[] arr = S.toCharArray();
Arrays.sort(arr);
boolean[] book = new boolean[arr.length];
dfs(list, new StringBuilder(), book, arr);
String[] res = new String[list.size()];
for (int i = 0; i < res.length; i++)
res[i] = list.get(i);
return res;
}
public void dfs(List res, StringBuilder sb, boolean[] book, char[] arr) {
if (sb.length() == arr.length) {
res.add(sb.toString());
return;
}
for (int i = 0; i < arr.length; i++) {
if (!book[i]) {
if (i > 0 && arr[i] == arr[i - 1] && !book[i - 1])
continue;
else {
sb.append(arr[i]);
book[i] = true;
dfs(res, sb, book, arr);
book[i] = false;
sb.deleteCharAt(sb.length() - 1);
}
}
}
}
Q8.9 括号
括号。设计一种算法,打印n对括号的所有合法的(例如,开闭一一对应)组合。
说明:解集不能包含重复的子集。
例如,给出 n = 3,生成结果为:
[
“((()))”,
“(()())”,
“(())()”,
“()(())”,
“()()()”
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/bracket-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
class Solution {
List result = new ArrayList();
public List generateParenthesis(int n) {
getAllResult(0, 0, n, new StringBuilder());
return result;
}
public void getAllResult(int pre, int last, int n, StringBuilder sb){
if(pre == n && last == n){
result.add(sb.toString());
return;
}
if(pre < n){
sb.append(‘(’);
getAllResult(pre + 1, last, n, sb);
sb.delete(sb.length() - 1, sb.length());
}
if(last < pre){
sb.append(‘)’);
getAllResult(pre, last + 1, n, sb);
sb.delete(sb.length() - 1, sb.length());
}
}
}
Q8.10 颜色填充
编写函数,实现许多图片编辑软件都支持的「颜色填充」功能。
待填充的图像用二维数组 image 表示,元素为初始颜色值。初始坐标点的横坐标为 sr 纵坐标为 sc。需要填充的新颜色为 newColor 。
「周围区域」是指颜色相同且在上、下、左、右四个方向上存在相连情况的若干元素。
请用新颜色填充初始坐标点的周围区域,并返回填充后的图像。
示例:
输入:
image = [[1,1,1],[1,1,0],[1,0,1]]
sr = 1, sc = 1, newColor = 2
输出:[[2,2,2],[2,2,0],[2,0,1]]
解释:
初始坐标点位于图像的正中间,坐标 (sr,sc)=(1,1) 。
初始坐标点周围区域上所有符合条件的像素点的颜色都被更改成 2 。
注意,右下角的像素没有更改为 2 ,因为它不属于初始坐标点的周围区域。
提示:
image 和 image[0] 的长度均在范围 [1, 50] 内。
初始坐标点 (sr,sc) 满足 0 <= sr < image.length 和 0 <= sc < image[0].length 。
image[i][j] 和 newColor 表示的颜色值在范围 [0, 65535] 内。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/color-fill-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
r代表row,c代表col,理解为x行x列
【附】相关架构及资料
源码、笔记、视频。高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术,和技术大牛一起讨论交流解决问题。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!
wColor = 2
输出:[[2,2,2],[2,2,0],[2,0,1]]
解释:
初始坐标点位于图像的正中间,坐标 (sr,sc)=(1,1) 。
初始坐标点周围区域上所有符合条件的像素点的颜色都被更改成 2 。
注意,右下角的像素没有更改为 2 ,因为它不属于初始坐标点的周围区域。
提示:
image 和 image[0] 的长度均在范围 [1, 50] 内。
初始坐标点 (sr,sc) 满足 0 <= sr < image.length 和 0 <= sc < image[0].length 。
image[i][j] 和 newColor 表示的颜色值在范围 [0, 65535] 内。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/color-fill-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
r代表row,c代表col,理解为x行x列
【附】相关架构及资料
源码、笔记、视频。高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术,和技术大牛一起讨论交流解决问题。
[外链图片转存中…(img-U9oj3IcQ-1715722587503)]
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!