回溯法

思路:理论上来讲是回溯法的思想,但是写完代码之后感觉就是递归。可能还没感受到回溯的精髓。

1.  因为访问过的位置不可再访问,必又一个标记矩阵记录是否已访问

2. 遍历矩阵,从每个节点出发。

3. 每访问一个节点都要判断当前节点是否为字符串str中的下一个元素,再判断其周围有没有下一个可走路径(递归调用)。

若周围四个位置都不可走,那么本节点也不可走。那么就返回起点,从下一个节点开始出发。

5. 若本节点可走,其周围又有可走路径。那么进入周围的下一个可走节点继续3步骤。(递归)

4. 直到字符串中的字符都走完,返回TRUE。若遍历完矩阵还没找到路径,那么返回FALSE。

class Solution {
public:
    bool hasPath(char* matrix, int rows, int cols, char* str)
    {
        if(matrix==NULL||rows<1||cols<1||str==NULL){
            return false;
        }
        bool* visited=new bool[rows*cols];
        memset(visited,0,rows*cols);
        int len=0;
        for(int row=0;row<rows;row++){  // 遍历起点
            for(int col=0;col<cols;col++){
                if(hasPathCore(matrix,rows,cols,row,col,len,str,visited)) 
                    return true;
            }
        }
        return false; // 该矩阵中不含str路径
    }
    bool hasPathCore(char* matrix,int rows,int cols,int row,int col,int len,
                    char* str,bool* visited){
        bool hasPath = false;
        if(str[len]=='\0')
            return true;
        if(row<0||row>=rows||col<0||col>=cols)
            return false;
        if(str[len]==matrix[row*cols+col] && !visited[row*cols+col]){ //判断是否可走
            len++;
            visited[row*cols+col]=true;
            
            hasPath=hasPathCore(matrix,rows,cols,row,col+1,len,str,visited)|| //判断其周围是否有可走路径
            hasPathCore(matrix,rows,cols,row,col-1,len,str,visited)||
            hasPathCore(matrix,rows,cols,row+1,col,len,str,visited)||
            hasPathCore(matrix,rows,cols,row-1,col,len,str,visited);
        
        if(!hasPath){ //周围没有可走路径,退回上一步
            visited[row*cols+col]=false;
            len--;
            }
        }
        return hasPath; 
    }
    

};

 

第一感觉和上一题差不多。但!又有小细节不一样。

每个格子可以走多次,但只可计算一次。所以在计算当前格子四周的格子的时候是把结果加起来,而不是取最大。

但是,直接计算满足条件的格子不就可以了么,为什么还要递归。(这个想法错了,又写了个遍历全部符合的格子,发现错误)

(错误原因:假如只有一行,阈值为10,当29的时候2+9>10,但是30就是3+0<10)

 

思路:

1. 同样有标记矩阵记录是否计算过当前节点。

2. 从固定点出发(0,0)

3. 针对每个节点,先判断当前节点是否可走,标记为已访问。然后计算四周节点一共可访问到多少节点,加上本节点,返回可访问节点数。

class Solution {
public:
    int movingCount(int threshold, int rows, int cols)
    {
        bool* visited=new bool[rows*cols];
        memset(visited,0,rows*cols);
        int count=movingCountCore(rows,cols,0,0,threshold,visited);
        return count;
    }
    int movingCountCore(int rows,int cols,int row,int col,int k,bool* visited){
        int count=0;
        if(row>=0&&row<rows&&col>=0&&col<cols&&!visited[row*cols+col]){
            if(enter(row,col,k)){
                count++;
                visited[row*cols+col]=true;
                count+=movingCountCore(rows,cols,row-1,col,k,visited)+
                    movingCountCore(rows,cols,row+1,col,k,visited)+
                    movingCountCore(rows,cols,row,col-1,k,visited)+
                    movingCountCore(rows,cols,row,col+1,k,visited);
            }
        }
        return count;
    }
    bool enter(int row,int col,int k){
        int t=1,m=1,sum=0;
        int h=10;
        while(row>0 || col>0){
            if(row>0){
                t=row%10;
                row/=10;
                sum+=t;
            }
            if(col>0){
                m=col%10;
                col/=10;
                sum+=m;
            }
        }
        if(sum>k) return false;
        else return true;
    }
};

 

上题依然采用回溯法,有点小曲折。本来想按层迭代,后来看到讨论区一个大神的分享,其每一层中每个规则也是一种迭代。

1. 给了当前层的节点,按照规则遍历,当规则可用时就在上一层的节点中加入一个字母。然后能不能成功就取决这一层后面的点能不能成功建立。

2. 当上一层的节点数比当前层少一个时说明该层建立成功。那么金字塔的建立能否成功就取决于上层能否建立。

3. 把上层的节点当作当前层,用迭代建立。

class Solution {
public:
    bool pyramidTransition(string bottom, vector<string>& allowed) {
        if(bottom=="") return true;
        return are_you_ok(bottom,"",allowed);
    }
    bool are_you_ok(string pre,string up,vector<string>& allowed){
        bool index;
        if(pre.size()==1){
            return true;
        }
        if(pre.size()-up.size()>1)
        {
            bool index=false;
            for(string s:allowed){
                if(pre[up.size()]==s[0]&&pre[up.size()+1]==s[1]){
                    index= index || are_you_ok(pre,up+s[2],allowed);
                }
                
            } 
            return index;
        }
        else{
           return are_you_ok(up,"",allowed);
        }

    
    }
};

 思路: 

就像一个二叉树,每遇到一个字母都有两个子节点。

1. 每遇到一个字母都只有两种情况,一个是变为大写,然后把变化后的字符串传出去遍历下一个字母(迭代)。

二是变为小写,跟上面是一样的情况。

2. 直到叶子节点就输出路径。到字符串的尾部是把经过一路更改最后接收到的字符串push进vector中。

class Solution {
public:
    vector<string> letterCasePermutation(string S) {
        vector<string> lists;
        looping(lists,S,0);
        return lists;
        
    }
    void looping(vector<string> &lists,string S,int i){
        if(S[i]=='\0'){
            lists.push_back(S);
            return ;
        }
        if(isalpha(S[i])){
            S[i]=tolower(S[i]);
            looping(lists,S,i+1);
            S[i]=toupper(S[i]);
            looping(lists,S,i+1);
        }
        else
            looping(lists,S,i+1);
        
    
  }
    char tolower(char s){
        if(s-'a'>=0){
            return s;
        }
        else
            return 'a'+(s-'A');
    }
    char toupper(char s){
        if(s-'a'>=0){
            return 'A'+(s-'a');
        }
        else
            return s;
    }
    int isalpha(char s){
        if(s>='A'&&s<='Z')
            return true;
        if(s>='a'&&s<='z')
            return true;
        return false;
    }
    
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值