剑指offer习题集2
1.把数组排成最小的数
class Solution { public: static bool compare(const string& s1, const string& s2) { string t1 = s1 + s2; string t2 = s2 + s1; return t1 <= t2? true : false; } string PrintMinNumber(vector<int> numbers) { string str; int i, len = numbers.size(); if (len<1) return str; string res; vector<string> vt; for (i = 0;i<len;++i) { stringstream stream; stream << numbers[i]; stream >> str; vt.push_back(str); } sort(vt.begin(), vt.end(), compare); for (i = 0;i<len;++i) res += vt[i]; return res; } };
这里使用string会比使用char*更加快捷方便。
另外使用sort而不是qsort,主要是sort是qsort的升级,且参数更少,不需要制定每个参数占据的内存空间大小。
2.字符流中第一个不重复的字符
少有的一遍通过的程序,眼泪都快流下来了
class Solution { public: Solution():index(0){ //初始化位置 for(int i=0;i<256;++i) pos[i]=-1; } //Insert one char from stringstream void Insert(char ch) { if(pos[ch]==-1) pos[ch]=index; else if(pos[ch]>=0) pos[ch]=-2; ++index; } //return the first appearence once char in current stringstream char FirstAppearingOnce() { char res='#'; int minv=1e8,i; //设置字符串max值 for(i=0;i<256;++i){ if(pos[i]>=0&&pos[i]<minv){ //若是当前位置小于min,则对min进行更新 res=(char)i; minv=pos[i]; } } return res; } private: int index; int pos[256]; };
3.求滑动窗口最大值
还是不能一遍通过,而且思维定式,真的很难找到错误的
class Solution { public: vector<int> maxInWindows(const vector<int>& num, unsigned int size) { int i,j,k,len=num.size(); vector<int> result; if(len<size||size==0) return result; int max=num[0]; for(i=1;i<size;++i){ //先寻找第一个窗口的最大值 if(max<num[i]) max=num[i]; } result.push_back(max); for(i=1;i<=(len-size);++i){ j=i+size-1; if(num[j]<max){ //判断最大值是否移出滑动窗口 if(num[i-1]!=max) result.push_back(max); else{ //确定最大值被移出滑动窗口,重新确定最大值 max=num[i]; for(k=i;k<=j;++k){ if(num[k]>max) max=num[k]; } result.push_back(max); } }else{ result.push_back(num[j]); max=num[j]; } } return result; } };
4.表示数值的字符串(最耗人心力的程序,没有之一)
有空多做几遍,绝对练耐心
class Solution { public: bool isdigit(const char& ch){ if(ch<='9'&&ch>='0') return true; else return false; } void scandigits(char** str){ while(**str!='\0'&&isdigit(**str)) ++(*str); } bool isexpand(char** str){ if(**str!='E'&&**str!='e') return false; ++(*str); if(**str=='+'||**str=='-') ++(*str); if(**str=='\0') return false; scandigits(str); return (**str=='\0')?true:false; } bool isNumeric(char* strt) { if(NULL==strt) return false; bool digit=true; char *str=strt; //排除符号干扰,找到第一个数字 while(str){ if(*str=='+'||*str=='-'){ ++str;break; }else if(isdigit(*str)){ break; //找到第一个数字 } } if(*str=='\0') return false; scandigits(&str); if(*str!='\0'){ //针对小数进行处理 if(*str=='.'){ ++str; scandigits(&str); if(*str=='e'||*str=='E') digit=isexpand(&str); }else if(*str=='E'||*str=='e'){ digit=isexpand(&str); }else{ digit=false; } } return digit&&(*str=='\0'); } };
5.字符串的排列
《剑指offer》上针对的是无重复字符串的全排列递归做法。
下面贴的是对重复字符进行处理了的全排列递归做法,为了通过测试集,对字符串进行了排序。
class Solution { public: vector<string> Permutation(string str) { vector<string> res; int len=str.length(); if(0==len) return res; else if(1==len){ res.push_back(str); return res; } int left=0,right=len-1; Permutation(str,left,right,res); sort(res.begin(),res.end()); return res; } //递归实现字符交换 void Permutation(string& str,int left,int right,vector<string>& res){ if(left==right){ res.push_back(str); }else{ for(int i=left;i<=right;++i){ if(isswap(str,left,i)){ swap(str[i],str[left]); Permutation(str,left+1,right,res); swap(str[i],str[left]); } } } } private: void swap(char& a,char& b){ char t=a;a=b;b=t; } bool isswap(const string& str,const int& left,const int& right){ for(int i=left;i<right;++i) if(str[i]==str[right]) return false; return true; } };
后续会添加相应的非递归做法。
另外,此题可以扩展为多个子问题,待后续一一解决。
6.求旋转数组的最小数
没有通过测试集,不过自行调试,觉得程序应该是正确的啊
class Solution { public: int minNumberInRotateArray(vector<int> rotateArray) { int len = rotateArray.size(); if (0 == len) return 0; else if (1 == len) return rotateArray[0]; int left = 0, right = len - 1, mid; while (rotateArray[left] >= rotateArray[right]) { if (right - left == 1) { mid = right;break; } mid = left + (right - left) / 2; //如果下标为left/right/mid指向的三个数字相等 if (rotateArray[left] == rotateArray[right] && rotateArray[left] == rotateArray[mid]) { //顺序查找最小元素 return mininorder(rotateArray, left, right); } if (rotateArray[mid] >= rotateArray[left]) { left = mid; } else if (rotateArray[mid] <= rotateArray[right]) { right = mid; } } return rotateArray[mid]; } private: int mininorder(const vector<int>& rotateArray, const int& left, const int& right) { int min = rotateArray[left]; for (int i = left + 1;i <= right;++i) { if (rotateArray[i]<min) min = rotateArray[i]; } return min; } };
7.扑克牌顺子
class Solution { public: bool IsContinuous( vector<int> numbers ) { int len=numbers.size(); if(len<=1) return false; //进行排序 sort(numbers.begin(),numbers.end()); int i=0,zeronum=0,gap,numgap=0; for(i=0;i<len;i++){ if(numbers[i]==0) ++zeronum; else break; } //从非零的下一个位置开始进行计算 for(i=i+1;i<len;++i){ gap=numbers[i]-numbers[i-1]; if(0==gap) return false; else if(1==gap) continue; else{ numgap+=gap-1; } } if(numgap<=zeronum) return true; else return false; } };
8.丑数
此题真的不太好理解,需要重复练习几遍方能理解贯通。
class Solution { public: int GetUglyNumber_Solution(int index) { if(0==index) return 0; else if(1==index) return 1; long long *uglynum=new long long[index]; uglynum[0]=1; int nextuglyindex=1; long long min,*p1=uglynum,*p2=uglynum,*p3=uglynum; while(nextuglyindex<index){ min=minnum(*p1*2,*p2*3,*p3*5); uglynum[nextuglyindex]=min; while(*p1*2<=uglynum[nextuglyindex]) ++p1; while(*p2*3<=uglynum[nextuglyindex]) ++p2; while(*p3*5<=uglynum[nextuglyindex]) ++p3; ++nextuglyindex; } int res= (int)uglynum[nextuglyindex-1]; delete[] uglynum; return res; } private: long long minnum(const long long& num1,const long long& num2,const long long& num3){ long long min=(num1<num2)?num1:num2; return (num3<min)?num3:min; } };
9.正则表达式匹配
class Solution { public: bool match(char* str, char* pattern) { if(NULL==str||pattern==NULL) return false; else return matchstr(str,pattern); } private: bool matchstr(char* str,char* pattern){ if(*str=='\0'&&*pattern=='\0') return true; if(*str!='\0'&&*pattern=='\0') return false; if(*(pattern+1)=='*'){ if(*pattern==*str||(*pattern=='.'&&*str!='\0')) return matchstr(str+1,pattern+2) || matchstr(str+1,pattern) || matchstr(str,pattern+2); else return matchstr(str,pattern+2); } if(*str==*pattern||(*pattern=='.'&&*str!='\0')) return matchstr(str+1,pattern+1); return false; } };
return使用||返回几个可能结果,状态之间的变化,简直不能再赞了
10.树的子结构
/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } };*/ class Solution { public: bool HasSubtree(TreeNode* root1, TreeNode* root2) { bool res=false; if(root1!=NULL&&root2!=NULL){ if(root1->val==root2->val){ res=judgetree(root1,root2); } if(!res) res=HasSubtree(root1->left,root2); if(!res) res=HasSubtree(root1->right,root2); } return res; } private: bool judgetree(TreeNode* root1, TreeNode* root2){ if(root2==NULL) return true; if(root1==NULL) return false; if(root1->val!=root2->val) return false; return judgetree(root1->left,root2->left)&& judgetree(root1->right,root2->right); } };
以后看看能不能改进,避免递归调用。
11.栈的压入弹出
class Solution { public: bool IsPopOrder(vector<int> push, vector<int> pop) { bool res = false; int len = push.size(); if (len != pop.size() || len <= 0) return res; stack<int> sdata; vector<int>::iterator nextpush = push.begin(), nextpop = pop.begin(); while (nextpop - pop.begin() < len) { while (sdata.empty() || sdata.top() != *nextpop) { if (nextpush - push.begin() == len) break; sdata.push(*nextpush); ++nextpush; } if (sdata.top() != *nextpop) break; sdata.pop(); nextpop++; } if (sdata.empty() && nextpop - pop.begin() == len) res = true; return res; } };
12.二叉搜索树的后序遍历序列
class Solution { public: bool VerifySquenceOfBST(vector<int> sdata) { int len = sdata.size(); if (len <= 0) return false; return judgeBST(sdata, 0, len - 1); } private: bool judgeBST(vector<int>& sdata, int left, int right) { if (right - left < 0) return false; int i, j, root = sdata[right]; for (i = left;i < right;++i) { if (sdata[i] > root) break; } for (j = i;j < right;++j) { if (sdata[j] < root) return false; } bool leftsign = true, rightsign = true; if (i > left) //表示有左子树 leftsign = judgeBST(sdata, left, i - 1); if (i < right) //表示有右子树 rightsign = judgeBST(sdata, i, right - 1); return (leftsign&&rightsign); } };
13.按之字形顺序打印二叉树
class Solution { public: vector<vector<int>> Print(TreeNode* root) { vector<vector<int>> res; if (NULL == root) return res; int i, left, right, nextlevel = 0, tobepush = 1; vector<int> vtmp; std::queue<TreeNode*> nodes; nodes.push(root); while (!nodes.empty()) { TreeNode *nodetmp = nodes.front(); vtmp.push_back(nodetmp->val); if (nodetmp->left) { ++nextlevel; nodes.push(nodetmp->left); } if (nodetmp->right) { ++nextlevel; nodes.push(nodetmp->right); } nodes.pop(); --tobepush; if (0 == tobepush) { res.push_back(vtmp); vtmp.clear(); tobepush = nextlevel; nextlevel = 0; } } for (i = 1; i < res.size(); i += 2) { left = 0;right = res[i].size() - 1; while (left < right) { swap(res[i][left], res[i][right]); ++left;--right; } } return res; } private: void swap(int& a, int& b) { int tmp = a;a = b;b = tmp; } };
14.判断二叉树是否对称
class Solution { public: bool isSymmetrical(TreeNode* pRoot) { if (NULL == pRoot) return true; else return judgeSymmetrical(pRoot->left, pRoot->right); } private: bool judgeSymmetrical(TreeNode* left, TreeNode* right) { if (NULL == left&&NULL == right) return true; if (NULL == left || NULL == right) return false; if (left->val != right->val) return false; //注意此处不能判断相等返回true,因为下面还要进行判断 return judgeSymmetrical(left->left, right->right) && judgeSymmetrical(left->right, right->left); } };
很完美的思路,通过前序序列进行判断。
15.二叉树的序列化和反序列化
class Solution { public: char* Serialize(TreeNode *root) { string str; Serialize(root, str); int i,len = str.length(); char *res = new char[len + 1]; for (i = 0; i < len; i++) res[i] = str[i]; res[i] = '\0'; return res; } TreeNode* Deserialize(char *str) { if (NULL == str || *str == '\0') return NULL; int left = 0; string numstr(str); TreeNode* head = Deserialize(numstr, left); return head; } private: void Serialize(TreeNode *root, string& str) { if (NULL == root) { str += "#,"; return; } else { ostringstream ost; ost << root->val; str += ost.str() + ','; } Serialize(root->left, str); Serialize(root->right, str); } bool readstr(string& str,int& left, int& num) { if (str[left] == '#') { left += 2; //退后至下一个数字 return false; } else { string tmp; while (str[left] != ',' && str[left] != '\0') { tmp += str[left++]; } ++left; num = atoi(tmp.c_str()); return true; } } TreeNode* Deserialize(string& numstr,int& left) { int num; if (readstr(numstr, left, num)) { TreeNode* root = new TreeNode(num); root->left = Deserialize(numstr, left); root->right = Deserialize(numstr, left); return root; } return NULL; } };
16.二叉搜索树的第K个节点
class Solution { public: TreeNode* KthNode(TreeNode* pRoot, unsigned int k) { if (NULL == pRoot || k == 0) return NULL; return KthTreeNode(pRoot, k); } private: TreeNode* KthTreeNode(TreeNode* root, unsigned int& k) { TreeNode* target = NULL; if (root->left != NULL) target = KthTreeNode(root->left, k); if (NULL == target) { if (k == 1) target = root; --k; } if (NULL == target&&root->right != NULL) target = KthTreeNode(root->right, k); return target; } };
根据中序遍历的方式实现寻找。