面试题 01.01. 判定字符是否唯一
class Solution {
public:
bool isUnique(string astr) {
// 方法一:使用set
// set setChar(astr.cbegin(),astr.cend());
// if(setChar.size() == astr.size())
// return true;
// return false;
// 方法二:bool数组
// vector vbool(26,false);
// for(auto s : astr){
// int index = s-'a';
// if(!vbool[index]){
// vbool[index] = true;
// }else{
// return false;
// }
// }
// return true;
// 方法三:位运算
/*基于位运算的方法:
我们可以使用一个int类型的变量(下文用mark表示)来代替长度为26的bool数组。假设这个变量占26个bit(在多数语言中,这个值一般不止26),那么我们可以把它看成000...00(26个0),这26个bit对应着26个字符,对于一个字符c,检查对应下标的bit值即可判断是否重复。那么难点在于如何检查?这里我们可以通过位运算来完成。首先计算出字符char离'a'这个字符的距离,即我们要位移的距离,用move_bit表示,那么使用左移运算符1 << move_bit则可以得到对应下标为1,其余下标为0的数,如字符char = 'c',则得到的数为000...00100,将这个数跟mark做与运算,由于这个数只有一个位为1,其他位为0,那么与运算的结果中,其他位肯定是0,而对应的下标位是否0则取决于之前这个字符有没有出现过,若出现过则被标记为1,那么与运算的结果就不为0;若之前没有出现过,则对应位的与运算的结果也是0,那么整个结果也为0。对于没有出现过的字符,我们用或运算mark | (1 << move_bit)将对应下标位的值置为1。*/
int mark = 0;
int move_bit = 0;
for(auto s : astr){
move_bit = s - 'a';
if(mark & (1 << move_bit)){
//如果与完之后还得1,说明该位已经有1了,重复了!
return false;
}else{
//说明该位之前不是1,应该把该位置1
mark |= (1 << move_bit);
}
}
return true;
}
};
面试题 01.02. 判定是否互为字符重排
class Solution {
public:
bool CheckPermutation(string s1, string s2) {
/*定义如下:1两字符串字符个数相等 2每个字符出现次数相同*/
if(s1.size() != s2.size()){
return false;
}
if(s1.size() == 0){
return true;
}
//此时,两者非空,且字符个数相等
vector<int> vi(26,0);
int index = 0;
for(auto char1 : s1){
index = char1 - 'a';
++ vi[index];
}
for(auto char2 : s2){
index = char2 - 'a';
if(vi[index] > 0){
-- vi[index];
}else{
return false;
}
}
for(auto i : vi){
if(i != 0)
return false;
}
return true;
}
};
面试题 01.03. URL化
class Solution {
public:
string replaceSpaces(string S, int length) {
int flag = S.size() - 1;
for(int i=length-1;i>=0;--i){
if(S[i] == ' '){
S[flag--] = '0';
S[flag--] = '2';
S[flag--] = '%';
}else{
S[flag--] = S[i];
}
}
if(flag >= 0){
S = S.substr(flag+1, S.size()-1);
}
return S;
}
};
面试题 01.04. 回文排列
class Solution {
public:
bool canPermutePalindrome(string s) {
//每个字符出现的次数为偶数, 或者有且只有一个字符出现的次数为奇数时, 是回文的排列; 否则不是
bitset<128> bs;
for(auto c : s){
bs.flip(c);
}
return bs.count() == 1 || bs.none();
}
};
面试题 01.05. 一次编辑
45%,100%
class Solution {
public:
bool oneEditAway(string first, string second) {
// 长度相差最多为1,否则必然不符合要求
int fsize = first.size();
int ssize = second.size();
if(abs(fsize - ssize) > 1){
return false;
}
// 如果两个字符串长度相等,且仅有0个或1个字符不同,符合要求
if(abs(fsize - ssize) == 0){
int flag = 0;
for(int i=0;i<fsize;++i){
if(first[i]!=second[i]){
++flag;
}
if(flag >= 2){
return false;
}
}
return true;
}
// 如果两个字符串长度相差为1,有两种情况(1)first更长,就看second添一个字符能否和first相同(2)first更短,就看second删一个字符能否和first相同
if(fsize - ssize == 1){
auto fbegin = first.cbegin(),fend = first.cend();
auto sbegin = second.cbegin(),send = second.cend();
while(fbegin != fend){
if(*fbegin == *sbegin){
++fbegin;
++sbegin;
}else{
++fbegin;
}
}
if(sbegin == send){
return true;
}
return false;
}
if(fsize - ssize == -1){
auto fbegin = first.cbegin(),fend = first.cend();
auto sbegin = second.cbegin(),send = second.cend();
while(sbegin != send){
if(*fbegin == *sbegin){
++fbegin;
++sbegin;
}else{
++sbegin;
}
}
if(fbegin == fend){
return true;
}
return false;
}
return false;//随便的,反正到不了这一步
}
};
其实插入字符选项和删除字符选项,是可以合并的:
class Solution {
public:
bool oneEditAway(string first, string second) {
// 长度相差最多为1,否则必然不符合要求
int fsize = first.size();
int ssize = second.size();
if(abs(fsize - ssize) > 1){
return false;
}
// 如果两个字符串长度相等,且仅有0个或1个字符不同,符合要求
if(abs(fsize - ssize) == 0){
int flag = 0;
for(int i=0;i<fsize;++i){
if(first[i]!=second[i]){
++flag;
}
if(flag >= 2){
return false;
}
}
return true;
}
// 如果两个字符串长度相差为1,有两种情况(1)first更长,就看second添一个字符能否和first相同(2)first更短,就看second删一个字符能否和first相同
if(fsize - ssize == 1){
return isEdited(first.begin(),first.end(),second.begin(),second.end());
}
if(fsize - ssize == -1){
return isEdited(second.begin(),second.end(),first.begin(),first.end());
}
return false;
}
bool isEdited(string::iterator longbegin,string::iterator longend,string::iterator shortbegin,string::iterator shortend){
while(longbegin != longend){
if(*longbegin == *shortbegin){
++longbegin;
++shortbegin;
}else{
++longbegin;
}
}
if(shortbegin == shortend){
return true;
}
return false;
}
};
利用双指针法,从两侧夹逼,涉及3个变量,1个i从左往右检查,另外两个是j和k,因为字符串的长度可能不同
class Solution {
public:
bool oneEditAway(string first, string second) {
if(first == second){
return true;
}
const int lengthfirst = first.size();
const int lengthsecond = second.size();
if(abs(lengthfirst - lengthsecond)>1){
return false;
}
int i=0, j=lengthfirst-1, k=lengthsecond-1;
while(i<lengthfirst && i<lengthsecond && first[i] == second[i]){
++i;
}
while(j>=0 && k>=0 && first[j] == second[k]){//这里要检查j和k是否等于0
--j;
--k;
}
return j-i<1 && k-i<1;
}
};
面试题 01.06. 字符串压缩
s += to_string(num)
和s = s + to_string(num)
是不一样的。前者是接在s后面,后者是新建一个临时s对象,复制右边的结果,相当耗时,应该选择前者写法。
class Solution {
public:
string compressString(string S) {
//检查字符串内容合法性
for(auto c : S){
if(c>='a' && c<='z' || c>='A' && c<='Z'){
continue;
}
return "";
}
//进行初步逻辑判断
if(S.size() <= 2){
return S;
}
string comstring;
int num = 0;
for(int i=1; i<S.size(); ++i){
if(S[i-1] == S[i]){
++num;
}else{
++num;
comstring += S[i-1] + to_string(num);
num = 0;
}
}
++num;
comstring += S[S.size()-1] + to_string(num);
return (comstring.size() > S.size())? S : comstring;
}
};
面试题 01.07. 旋转矩阵
这个n平方,n平方的方法反而100%,100%
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int len = matrix.size();
auto matrixfb = matrix;
for(int i=0;i<len;++i){
for(int j=0;j<len;++j){
matrixfb[j][len-i-1] = matrix[i][j];
}
}
matrix = matrixfb;
return;
}
};
下面这个靠旋转推导出的关系:
反倒56%,100%
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
int tmp;
for(int row=0;row<n/2;++row){
for(int col=0;col<(n+1)/2;++col){
tmp = matrix[row][col];
matrix[row][col] = matrix[n-col-1][row];
matrix[n-col-1][row] = matrix[n-row-1][n-col-1];
matrix[n-row-1][n-col-1] = matrix[col][n-row-1];
matrix[col][n-row-1] = tmp;
}
}
}
};
先上下翻转,再沿主对角线翻转:
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
// 上下翻转
for(int i=0;i<n/2;++i){
for(int j=0;j<n;++j){
swap(matrix[i][j],matrix[n-i-1][j]);
}
}
// 沿主对角线翻转
for(int i=0;i<n;++i){
for(int j=0;j<i;++j){
swap(matrix[i][j],matrix[j][i]);
}
}
}
};
面试题 01.08. 零矩阵
利用bool数组:
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
int row = matrix.size();
int col = matrix[0].size();
if(row == 0 || col == 0){
return;
}
vector<bool> vboolrow(row,false);
vector<bool> vboolcol(col,false);
for(int i=0;i<row;++i){
for(int j=0;j<col;++j){
if(matrix[i][j] == 0){
vboolrow[i] = true;
vboolcol[j] = true;
}
}
}
for(int i=0;i<row;++i){
for(int j=0;j<col;++j){
if(vboolrow[i] == true || vboolcol[j] == true){
matrix[i][j] = 0;
}
}
}
}
};
利用set:
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
unordered_set<int> row_set, col_set;
size_t row = matrix.size(), col = matrix[0].size();
for (size_t i = 0; i < row; ++i)
for (size_t j = 0; j < col; ++j)
if (matrix[i][j] == 0) {
row_set.insert(i);
col_set.insert(j);
}
for (const auto& row_idx : row_set)
matrix[row_idx].assign(col, 0);
// for (size_t i = 0; i < col; ++i)
// matrix[row_idx][i] = 0;
for (const auto& col_idx : col_set) {
for (size_t i = 0; i < row; ++i)
matrix[i][col_idx] = 0;
}
}
};
面试题 01.09. 字符串轮转
class Solution {
public:
bool isFlipedString(string s1, string s2) {
int ss1 = s1.size(),ss2 = s2.size();
if(ss1 != ss2){
return false;
}
// return (s2+s2).find(s1)!= -1;
return (s1+s1).find(s2)!= -1;
}
};