zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    linux 安装 Chrome
    J2EE版本
    Java 源码解析之局部变量检查
    /etc/xinetd.conf 和 /etc/xinetd.d/*【新网络服务配置】
    Linux 内核编译
    linux 汇编
    /etc/ethers【地址映射】
    Linux LAMP 搭建
    Linux ftp 使用
    linux apache
  • 原文地址:https://www.cnblogs.com/qmillet/p/12076774.html
Copyright © 2011-2022 走看看