文章目录
- 8.1三步问题
- 8.2迷路的机器人
- 8.3魔术索引
- 8.4求幂集
- 8.5递归乘法
- 8.6 汉诺塔
- 8.7无重复字符串的排列组合(☆)
- 8.8有重复字符的排列组合
- 8.9括号
- 8.10颜色填充
- 8.11硬币
- 8.12八皇后
8.1三步问题
一个基础的动态规划问题,pass
dp[i]=dp[i-1] + dp[i-2] +dp[i-3]
dp[1]=1, dp[2]=2, dp[3]=4
class Solution {
public int waysToStep(int n) {
if(n==1) return 1;
if(n==2) return 2;
if(n==3) return 4;
int a=1,b=2,c=4;
int ans=0;
for(int i=4;i<=n;i++){
ans=((a+b)%1000000007+c)%1000000007;
a=b;
b=c;
c=ans;
}
return ans%1000000007;
}
}
8.2迷路的机器人
class Solution {
public List<List<Integer>> pathWithObstacles(int[][] obstacleGrid) {
int row = obstacleGrid.length;
int col = obstacleGrid[0].length;
List<List<Integer>> list = new ArrayList<>();
boolean[][] dp = new boolean[row][col];
if(obstacleGrid[0][0] == 1 || obstacleGrid[row - 1][col - 1] == 1) return list;
dp[0][0] = true;
for(int i = 0; i < row; i++){
for(int j = 0; j < col; j++){
if(obstacleGrid[i][j] == 0){
if(i > 0){
dp[i][j] |= dp[i - 1][j];
}
if(j > 0){
dp[i][j] |= dp[i][j - 1];
}
}
}
}
if(!dp[row - 1][col - 1]) return list;
int i = row -1, j = col - 1;
while(i >= 0 && j >= 0){
list.add(Arrays.asList(i, j));
if(i > 0 && dp[i - 1][j]){
i--;
} else {
j--;
}
}
Collections.reverse(list);
return list;
}
}
先用动态规划的方法搜寻每个位置能不能到,如果能到最终位置,再反向回到(0,0),反正只要一条路即可
注意两个java操作的小细节:
list.add(Arrays.asList(i, j));
Collections.reverse(list);
8.3魔术索引
class Solution {
public int findMagicIndex(int[] nums) {
for(int i=0;i<nums.length; ){
if(nums[i]==i)
return i;
i=Math.max(nums[i],i+1);
}
return -1;
}
}
间隔跳跃索引,pass
8.4求幂集
可以看我以前写的博客->求幂集的更新贴
8.5递归乘法
public int multiply(int A, int B) {
int min = Math.min(A, B);
int max = Math.max(A, B);
int ans = 0;
for (int i = 0; min != 0; i++) {
if ((min & 1) == 1) {
ans += max << i;
}
min >>= 1;
}
return ans;
}
思路
首先,求得A和B的最小值和最大值;
然后,可以对其中的最小值当做乘数(为什么选最小值,因为选最小值当乘数,可以算的少),将其拆分成2的幂的和,即
min =
a
0
a_0
a0
2
0
2^0
20+
a
1
a_1
a1
2
1
2^1
21+…+
a
i
a_i
ai*
2
i
2^i
2i+… , 其中
a
i
a_i
ai取0或者1.
其实就是用二进制的视角去看待min,比如12用二进制表示就是1100,即1000+0100。举个例子,13 * 12 = 13 * (8 + 4) = 13 * 8 + 13 * 4 = (13 << 3) + (13 << 2);
8.6 汉诺塔
class Solution {
public void hanota(List<Integer> A, List<Integer> B, List<Integer> C) {
moveA2C(A,B,C,A.size());
}
public void moveA2C(List<Integer>A,List<Integer>B,List<Integer>C,int n){
if(n==1){
C.add(A.remove(A.size()-1));
return ;
}
moveA2C(A, C, B, n - 1); //A中N-1层移到B
moveA2C(A, B, C, 1); //A中最后一层移到C
moveA2C(B, A, C, n-1); //B的N-1层移到C
}
}
主要还是注意终止条件,三个子递归倒是很自然。
remove的必须是A.size()-1, 而不能是0.
8.7无重复字符串的排列组合(☆)
非递归和递归的写法
以前我是用C++的next_permutation写的
class Solution {
public:
vector<string> permutation(string S) {
sort(S.begin(), S.end());
vector<string> res;
res.push_back(S);
while(next_permutation(S.begin(), S.end())) {
res.push_back(S);
}
return res;
}
};
不过Java里面没有这个函数。(当然也可能有,但我懒的去查了)
但是DFS我又不是太懂这个swap
class Solution {
List<String> list = new ArrayList<>();
public String[] permutation(String S) {
permutate(S.toCharArray(), 0);
String[] res = new String[list.size()];
for (int i = 0; i < res.length; i++) {
res[i] = list.get(i);
}
return res;
}
public void permutate(char[] arr, int first) {
if (first == arr.length - 1) {
list.add(new String(arr));
return;
}
for (int i = first; i < arr.length; i++) {
swap(arr, first, i);
permutate(arr, first + 1);
swap(arr, first, i);
}
}
public void swap(char[] arr, int i, int j) {
char temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
8.8有重复字符的排列组合
发现这俩就是代码随想录里的9.12和9.13,排列问题(一)和排列问题(二)
8.9括号
class Solution {
List<String> res = new ArrayList<>();
public List<String> generateParenthesis(int n) {
dfs(n, n, "");
return res;
}
private void dfs(int left, int right, String curStr) {
if (left == 0 && right == 0) { // 左右括号都不剩余了,递归终止
res.add(curStr);
return;
}
if (left > 0) { // 如果左括号还剩余的话,可以拼接左括号
dfs(left - 1, right, curStr + "(");
}
if (right > left) { // 如果右括号剩余多于左括号剩余的话,可以拼接右括号
dfs(left, right - 1, curStr + ")");
}
}
}
8.10颜色填充
class Solution {
public int[][] floodFill(int[][] image, int sr, int sc, int newColor) {
helper(image, sr, sc, image[sr][sc], newColor);
return image;
}
private void helper(int[][] image, int i, int j, int oldColor, int newColor){
if(i < 0 || i >= image.length || j < 0 || j >= image[0].length || image[i][j] != oldColor || image[i][j] == newColor) return;
image[i][j] = newColor;
helper(image, i+1, j, oldColor, newColor);
helper(image, i-1, j, oldColor, newColor);
helper(image, i, j+1, oldColor, newColor);
helper(image, i, j-1, oldColor, newColor);
}
}
对上下左右进行修改。再以此为扩展。
如果不是一个岛屿内的(image[i][j]!=oldColor)或者已经被修改过了(image[i][j]==newColor),就不用再改了,直接return;
8.11硬币
完全背包问题
class Solution {
private final int mod = 1000000007;
private final int[] coins = {25,10,5,1};
public int waysToChange(int n) {
int[] dp = new int[n + 1];
dp[0] = 1;
for(int coin : coins){
for(int i = coin;i <= n;i++){
dp[i] = (dp[i] + dp[i - coin]) % mod;
}
}
return dp[n];
}
}
8.12八皇后
class Solution {
private List<List<String>> res = new ArrayList<>(); // 最终答案
public List<List<String>> solveNQueens(int n) {
char[][] grid = new char[n][n]; // 定义棋盘
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
grid[i][j] = '.'; // 棋盘初始化默认都是空
}
}
// 占用为true,未占用false
// 记录第k列有没有被占用
boolean[] col = new boolean[n];
// 记录主对角线方向有没有被占用(左上到右下)
// 该方向的x=row-col是固定的,范围为-n+1~n-1共2n-1个数,n-x之后范围是1~2n-1,用2n的数组就可以容纳
boolean[] mainDiag = new boolean[2*n];
// 记录副对角线方向有没有被占用(右上到左下)
// 该方向的x=row+col是固定的,范围为0~2n-2共2n-1个数,用2n的数组也可以表示2n-1条对角方向
boolean[] subDiag = new boolean[2*n];
dfs(0, n, grid, col, mainDiag, subDiag); // 利用dfs为每一个皇后搜索摆放位置
return res;
}
// 策略为每个皇后摆放一行,r代表当前摆放到行index, n为皇后个数,grid棋盘,后面3个冲突检查数组
public void dfs(int r, int n, char[][] grid, boolean[] col, boolean[] mainDiag, boolean[] subDiag){
if(r == n){ // 当最后一个皇后摆放完毕(任务成昆!)
List<String> list = new ArrayList<>(); // 新list记录当前此种摆放结果
for(int i=0;i<n;i++){ // 每一行
list.add(new String(grid[i])); // 将char[]转成String添加进去
}
res.add(list); // 此种摆放结果添加到结果集
return;
}
for(int c=0;c<n;c++){ // 对每一列遍历(摆放女王,列也不能重复)
// 该列空,该位置主对角线方向空,该位置副对角线方向空
if(!col[c] && !mainDiag[n-r+c] && !subDiag[r+c]){
// 可以摆放,棋盘记录
grid[r][c] = 'Q';
// 更新冲突数组
col[c] = mainDiag[n-r+c] = subDiag[r+c] = true;
// 摆放下一个皇后
dfs(r+1, n, grid, col, mainDiag, subDiag);
// 撤销操作,不影响下一次摆放
col[c] = mainDiag[n-r+c] = subDiag[r+c] = false;
grid[r][c] = '.';
}
}
}
}