字符串的处理
机器人的运动范围
题目描述
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
思路
做的时候不能忘记了,如果某个各自是限制访问的数字,则不能在这个各自上进行上下左右的搜索
class Solution {
public:
int availableGrid = 0;
int r = 0;
int c = 0;
int k = 0;
int deltaI[4] = {-1,0,+1,0};
int deltaJ[4] = {0,+1,0,-1};
bool largerThanK(int k, int i, int j){
int res=0;
while(i){
res+=(i%10);
i/=10;
}
while(j){
res+=(j%10);
j/=10;
}
if(res>k)return false;
return true;
}
void search(int i,int j,vector<vector<int>>&map){
if(i<0||i>=r||j<0||j>=c){
return ; // 越界就不在搜索
}
if(map[i][j]!=-1||!largerThanK(k,i,j)){
return; // 当前位置访问过或者不复合条件则停止搜索 不在进行下面的搜索
}
map[i][j] = 1;
availableGrid++;
for(int di=0;di<4;di++){
//printf("下一格:%d,%d",i+deltaI[di],j+deltaJ[di]);
search(i+deltaI[di],j+deltaJ[di],map);
}
// 这个问题是不需要回溯的,能访问的格子会被慢慢的访问完。
}
int movingCount(int threshold, int rows, int cols)
{
k = threshold;
r = rows;
c = cols;
// map用来记录格子是否访问过
vector< vector<int> >map(rows,vector<int>(cols,-1));
search(0,0,map);
return availableGrid;
}
};
矩阵中的路径
题目描述
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如
矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
思路
深度优先搜索+回溯
class Solution {
public:
char *map = 0; // 以map[c*i+j] 的方式 实现map[i][j]
int r = 0; // 地图的行数
int c = 0; // 地图的列数
int len = 0;// 目标字符串的长度
int dir[5] = {-1,0,1,0,-1}; // 巧妙的方向控制 x+d[i] y+d[i+1] for i=0~3 就能实现 上右下左
bool dfs(int i, int j, int pos, char* str){
/**
需要传入参数与 i j 当前的位置
pos 已匹配的字符长度 【这个同时也是当前需要匹配的目标字符的下标!!!】
str 目标字符串
*/
// 1.边界判断
if(i<0||i>=r||j<0||j>=c){
// 说明越界了还是没有找到,
return false;
}
// 2.判断是否访问过(题目要求访问过的不能再次访问) 访问过的字符会被替换成'#'
// 判断当前的字符是否符合要求 未访问过+与目标字符串中下一个字符相等
char curCh = map[i*c + j];
if(curCh=='#'||curCh!=str[pos]){
return false; // 当前位置访问过 或是 与当前需要匹配的目标字符不相等 都返回false
}
// 3.如果当前位置没有被访问过且与当前需要匹配的目标字符相等
// 3.1 需要检查是否匹配到最后
if(pos+1==len){
return true;
}
// 3.2 如果没有匹配到最后 继续搜索
map[i*c + j] = '#'; // 设置成特殊字符 表示访问过
for(int di=0;di<4;di++){
// 这里不需要去改变pos 直接传入一个pos就不用做pos的回溯了
if(dfs(i+dir[di],j+dir[di+1],pos+1,str))return true;
}
// 4.如果当前位置四个方向都匹配失败,说明从当前位置开始匹配剩下的部分失败
// 4.1 当前位置设置成未访问过的形式
map[i*c + j] = curCh;
// 4.2 返回匹配失败
return false;
}
bool hasPath(char* matrix, int rows, int cols, char* str)
{
map = matrix;
r = rows;
c = cols;
len = strlen(str); // 传入一个字符指针 返回字符串的长度 注意函数名不要和变量名重名
for(int i=0;i<rows;i++){
for(int j=0;j<cols;j++){
if(dfs(i,j,0,str)){
return true;
}
}
}
return false;
}
};
字符串的排列
题目描述
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则按字典序打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
思路
深搜+回溯 的 排列组合 同时还要去重
class Solution {
public:
void perm(string str, int pos, vector<string>&res){
// 1.当前遍历到最后一个字符位置
if(pos+1==str.size()){
res.push_back(str);
return ;
}
// 2.将str[pos]到最后一个字符 都放在pos上 然后全排列pos之后的字符串 perm(s,pos+1,res);
// 这里是遍历从pos开始的后缀子串的起始字符
for(int i=pos;i<str.size();i++){
// 2.1如果pos到i这个区间里面 有字符和str[i]相等,比如str[i]=a,pos到i之间已经有个a了 这种情况就是重复了 跳过
if(check(str, pos, i))continue;
// 2.2 让str[pos]到最后一个字符 都在pos上待一次
swap(str[pos], str[i]);
// 2.3 接下来只交换str中pos之后的部分
perm(str, pos+1, res);
// 2.4 回溯 以便原str[pos]与下一个str[i]交换 pos与i之间的字符顺序都是和str进来的时候一样的
swap(str[pos], str[i]);
}
}
bool check(string str, int start, int end){
// str[end]是待放到pos处的字符,如果pos到end之间有出现过该字符,则重复,不再搜索,返回true,当for continue
for(int i=start; i<end;i++){
if(str[i]==str[end])return true;
}
// pos到end之间没有出现过该字符,返回false搜索
return false;
}
vector<string> Permutation(string str) {
vector<string>res;
if(str=="")return res;
perm(str, 0, res);
// 需要按照字典序排序 也可以使用set去重 按字典序排序
sort(res.begin(), res.end());
return res;
}
};
把字符串转换成整数
题目描述
将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0
思路
1)先取出符号,方便处理,返回结果的时候再将符号加上
2)主要是针对范围非法的数字的判断
// 这里需要排除下字符串正好等于 -LLONG_MAX-1等情况
// -LLONG_MAX-1 ~ 0 ~ LLONG_MAX
class Solution {
public:
int StrToInt(string str) {
if(str.size()==0)return 0;
long long res=0;
int i=0;
char ch = str[0];
int flag=0; // 符号标记 正数为0,负数为1
// 1.先判断数的符号
// 1.1如果第一个字符不是 + - 号或是数组 直接就是非法字符返回0
if(ch!='+'&&ch!='-'&&!(ch-'0'>=0&&ch-'0'<=9))return 0;
if(ch=='+'||ch=='-'){
i = 1;
if(ch=='-')flag=1;
}
// 2.开始判断整串数是否合法
for(;i<str.size();i++){
ch = str[i];
// 2.1 扫描到非数字字符就返回0
if(!(ch-'0'>=0&&ch-'0'<=9))return 0;
else{
// 2.2 先将原结果res*10再加上当前的数 判断是否移出
// 如果res*10比res还小,说明说已经超出最大能表示的范围
// 这里LLONG_MAX=最末尾不是0或者9 所以*10不可能正好变成最大值
if(res*10<res)return 0;
res*=10;
// 2.3 加上当前扫描到的数,要判断是否溢出
if(res+(ch-'0')<res){
// -LLONG_MAX-1 ~ 0 ~ LLONG_MAX
// 这里需要排除下字符串正好等于 -LLONG_MAX-1的情况
if(res==LLONG_MAX&&(ch-'0')==1&&flag==1&&i==str.size()-1){
res+=1; // 【整数最大+1之后会变成负数最小】-LLONG_MAX-1
return res;
}else return 0;
}
res+=(ch-'0');
}
}
if(flag==1)return -res;
return res;
}
};
表示数值的字符串
题目描述
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100",“5e2”,"-123",“3.1416"和”-1E-16"都表示数值。 但是"12e",“1a3.14”,“1.2.3”,"±5"和"12e+4.3"都不是。
class Solution {
public:
bool isNumeric(char* string)
{
// 1.先判断是否含有e E 返回其所在的位置
int i=0;
int containE = -1;
while(string[i]!='\0'){
// printf("%c",string[i]);
if(string[i]=='e'||string[i]=='E'){
containE = i;
}
i++;
}
if(containE==i-1)return false;
if(containE==i-2){
if(string[i-1]-'0'<0||string[i-1]-'0'>9){
return false;
}
}
int strLen = i;
int pointAppear = 0;
int end;
if(containE==-1)end = strLen;
else{
end = containE;
}
for(int j=0;j<end;j++){
if(string[j]=='+'||string[j]=='-'){
if(j!=0)return false;
}
if(string[j]!='+'&&string[j]!='-'&&(string[j]-'0'<0||string[j]-'0'>9)&&string[j]!='.'){
return false;
}
if(string[j]=='.'){
if(j==0||j==containE-1){
//cout<<"1"<<endl;
return false;
}
if((string[j-1]-'0'<0||string[j-1]-'0'>9)&&string[j-1]!='+'&&string[j-1]!='-'){
//cout<<"2"<<endl;
return false;
}
if(string[j+1]-'0'<0||string[j+1]-'0'>9){
//cout<<"3"<<endl;
return false;
}
if(pointAppear==1){
//cout<<"4"<<endl;
return false;
}
else{
pointAppear=1;
}
}
}
//cout<<strLen<<endl;
for(int j=containE+1;j<strLen&&containE!=-1;j++){
//cout<<"判断右侧"<<endl;
if(string[j]=='+'&&string[j]=='-'){
if(j!=containE+1)return false;
}
if(string[j]!='+'&&string[j]!='-'&&(string[j]-'0'<0||string[j]-'0'>9)){
return false;
}
}
return true;
}
};
翻转单词顺序列
题目描述
牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?
思路
class Solution {
public:
string ReverseSentence(string str) {
if(str==""||str.size()==1)return str;
stack<string>charS;
int flag = 0;
int begin=-1;
int end=-1;
string res="";
// 1.先预处理下,处理掉两端的空白
for(int i=0;i<str.size();i++){
if(str[i]!=' '){
begin = i;
break;
}
}
for(int i=str.size()-1;i>=0;i--){
if(str[i]!=' '){
end = i;
break;
}
}
// 2.处理字符全为空格的情况
if(begin==-1)return str;
// 3.正式处理
string tmp = "";
for(int i=0;i<str.size();i++){
if(str[i]==' '){
if(res=="")res = tmp + res;
else res = tmp + " " + res;
tmp="";
}else{
tmp.push_back(str[i]);
}
if(i==end){
if(res=="")res = tmp + res;
else res = tmp + " " + res;
}
}
/*
// 4.这里可以处理 结果需要保留原字符串中空格的情况
while(begin--){
res = res + " ";
}
while((str.size()-1-end--)){
res = " " + res;
}
*/
return res;
}
};