思路:理论上来讲是回溯法的思想,但是写完代码之后感觉就是递归。可能还没感受到回溯的精髓。
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;
}
};