18. 回溯法&动态规划与贪婪

题一:【矩阵中的路径】

请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如 a b c e s f c s a d e e 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。

 分析:回溯DFS???需要设置一个flag数组标志是否已经遍历过。如果当前数组当前元素相等,则比较下一个元素(上下左右4种可能,但实际只有3种,只要有一个满足即可)。

 1 public class Solution {
 2     public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
 3     {
 4         if(str.length>rows*cols) return false;
 5         //标志位,标志数组内某位置元素是否已经在走过的路径中,默认为false
 6         boolean[] flag = new boolean[matrix.length];
 7         for(int i=0;i<rows;i++){
 8             for(int j=0;j<cols;j++){
 9                 int k = 0;//str进行比较的位置索引
10                 //先判断第一个元素减少点时间
11                 if(matrix[i*cols+j]==str[k]&&judgeNext(matrix,i,j,k,rows,cols,str,flag)){
12                     return true;
13                 }
14             }
15         }
16         return false;
17     }
18     public boolean judgeNext(char[] matrix, int i, int j, int k, int rows, int cols, char[] str, boolean[] flag){
19         int index = i*cols+j;
20         if(i<0||i>=rows||
21            j<0||j>=cols||
22            matrix[index]!=str[k]||//判断是否相等
23            flag[index]==true) //表示不能重走已经走过的路径
24         {
25             return false;
26         }
27         flag[index]=true;//表示当前位置元素正在走,或者是试探性走。置为true,让依照本元素走的路径不在重走本元素。
28         if(k==str.length-1) return true;//走完了
29         if(judgeNext(matrix,i-1,j,k+1,rows,cols,str,flag)||
30            judgeNext(matrix,i+1,j,k+1,rows,cols,str,flag)||
31            judgeNext(matrix,i,j-1,k+1,rows,cols,str,flag)||
32            judgeNext(matrix,i,j+1,k+1,rows,cols,str,flag))
33         {
34             return true;
35         }
36         flag[index]=false;//如果没有走到这步说明当前位置元素满足条件。如果走到这步说明不符合条件,需要重新置为false。
37         return false;
38     }
39 
40 }

题二:【机器人的运动范围】

地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?

 分析:和上题类似,定义一个flag二维数组,记录是否移动过

 1 public class Solution {
 2     public int movingCount(int threshold, int rows, int cols)
 3     {
 4         int[][] flag = new int[rows][cols];//默认全是0
 5         return countCell(0,0,threshold,rows,cols,flag);
 6     }
 7     public int countCell(int i, int j, int threshold, int rows, int cols, int[][] flag){
 8         if(i<0||i>=rows||
 9            j<0||j>=cols||
10            judge(i,j,threshold)==false||
11            flag[i][j]==1)
12         {
13             return 0;
14         }
15         flag[i][j] = 1;
16         return countCell(i+1,j,threshold,rows,cols,flag)+
17                countCell(i-1,j,threshold,rows,cols,flag)+
18                countCell(i,j+1,threshold,rows,cols,flag)+
19                countCell(i,j-1,threshold,rows,cols,flag)+1;
20     }
21     /**
22     判断当前格子是否满足要求
23     */
24     public boolean judge(int i, int j, int threshold){
25         int remainder1=0, remainder2=0;
26         while(i!=0){
27             remainder1 += i%10;//各位和
28             i = i/10;
29         }
30         while(j!=0){
31             remainder2 += j%10;
32             j = j/10;
33         }
34         if(remainder1+remainder2<=threshold){
35             return true;
36         }else{
37             return false;
38         }
39     }
40 }

题三:【剪绳子】

给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1],...,k[m]。请问k[0]xk[1]x...xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。输入一个数n,意义见题面。(2 <= n <= 60),输出答案。例如输入:8,输出:18.

分析:根据题意,找出乘积最大的m个数(这m个数的和为n)。

法一:DP:f(n) = max{ f(i) * f(n-i) },n剪成i和n-i两大段,其中f(i),f(n-i)再次划分成两小段,将大问题不断划分成小问题。需要定义一个数组,表示长度为i时的最佳分段的乘积(即最大乘积).

 1 public class Solution {
 2     public int cutRope(int target) {
 3         if(target<2) return 0;
 4         if(target==2) return 1;
 5         if(target==3) return 2;
 6         //temp数组中第i个元素表示把长度为i的绳子分成若干段之后的最大乘积
 7         //0,1,2,3位置上设置值便于计算
 8         int[] temp = new int[target+1];
 9         temp[0] = 0;
10         temp[1] = 1;
11         temp[2] = 2;
12         temp[3] = 3;
13         for(int i=4;i<target+1;i++){//填写数组,当长度为i时的最佳选择
14             int max = 0;
15             for(int j=1;j<=i/2;j++){//j<i/2是因为 4分成1、3和3、1是一样的
16                 int product = temp[j]*temp[i-j];
17                 if(max<product){
18                     max = product;
19                 }
20             }
21             temp[i]=max;
22         }
23         return temp[target];//temp最后一个元素就是当i=target时的最佳选择
24     }
25 }

法:贪婪:

  n=4 2*2

  n=5 2*3

  n=6 3*3

  n=7 3*2*2

  n=8 3*3*2

  n=9 3*3*3

  当x>5时,2*(x-2)>x,3*(x-3)>x,因此,一个长度为n的一段绳子最好能划分成2或3,又因为3*(x-3)>2*(x-2),因此要尽可能多的划分成3.例如当n=11时,3*(11-3)>11,3*(8-3)>8,3*(5-3)>5,因此n=11时,划分过程为3、8—3、3、5——3、3、3、2。注意:当x等于4的时候,最佳剪成2+2。

 1 import java.lang.Math;
 2 public class Solution {
 3     public int cutRope(int target) {
 4         if(target<2) return 0;
 5         if(target==2) return 1;
 6         if(target==3) return 2;
 7         int timesOfTwo=0,timesOfThree=0;
 8         timesOfThree = target/3;
 9         if((target-3*(timesOfThree-1))==4){
10             timesOfThree -= 1;
11         }
12         timesOfTwo = (target-timesOfThree*3)/2;
13         return (int)(Math.pow(2,timesOfTwo)*Math.pow(3,timesOfThree));
14     }
15 }

猜你喜欢

转载自www.cnblogs.com/qmillet/p/12076774.html
18.