剑指offer习题集1
1.打印二叉树
程序很简单,但是其中犯了一个小错误,死活找不到,写代码要注意啊
这里左右子树,要注意是node->left,结果写成root->left
vector<int> PrintFromTopToBottom(TreeNode *root) { vector<int> res; if (NULL == root) return res; TreeNode* node; deque<TreeNode*> tmp; tmp.push_back(root); while (tmp.size()) { node = tmp.front(); res.push_back(node->val); tmp.pop_front(); if (node->left) tmp.push_back(node->left); if (node->right) tmp.push_back(node->right); } return res; }
2.求1+2+...+n
class A{ public: A(){ ++n;sum+=n; } static int getsum(){ return sum; } static void reset(){ n=0;sum=0; } ~A(){} private: static int n; static int sum; }; int A::n=0; int A::sum=0; class Solution { public: int Sum_Solution(int n) { A::reset(); //必不可少,测试集会重复运行 A* tmp=new A[n]; delete[] tmp; return A::getsum(); } };
3.二叉树镜像
class Solution { public: void Mirror(TreeNode *pRoot) { if(NULL==pRoot||(NULL==pRoot->left&&NULL==pRoot->right)) return; mirrorset(pRoot); } void mirrorset(TreeNode* root){ if(NULL==root||(NULL==root->left&&NULL==root->right)) return; TreeNode *tmp=root->left; root->left=root->right; root->right=tmp; if(root->left) mirrorset(root->left); if(root->right) mirrorset(root->right); } };
4.合并两个排序的链表
剑指offer书上用的是递归,感觉不必那么麻烦,用一个循环就可以解决。
ListNode1* Merge(ListNode1* pHead1, ListNode1* pHead2) { //避免空指针 if (NULL == pHead1 || NULL == pHead2) return NULL == pHead1 ? pHead2 : pHead1; //选取两个链表中的最小值作为链表头 bool sign[2] = { false }; ListNode1 *p1 = pHead1, *p2 = pHead2, *p3, *res; if (p1->val < p2->val) { res = p1;p3 = res;p1 = p1->next;sign[0] = true; } else { res = p2;p3 = res;p2 = p2->next;sign[1] = true; } while (p1&&p2) { if (p1->val < p2->val) { if (sign[0]) { p1 = p1->next; p3 = p3->next; } else { p3->next = p1; p1 = p1->next; p3 = p3->next; } sign[0] = true;sign[1] = false; } else { if (sign[1]) { p2 = p2->next; p3 = p3->next; } else { p3->next = p2; p2 = p2->next; p3 = p3->next; } sign[0] = false;sign[1] = true; } } if (p1) { p3->next = p1; } else if (p2) { p3->next = p2; } return res; }
5.复杂链表的复制
/* struct RandomListNode { int label; struct RandomListNode *next, *random; RandomListNode(int x) : label(x), next(NULL), random(NULL) { } }; */ class Solution { public: RandomListNode* Clone(RandomListNode* pHead) { if(NULL==pHead) return NULL; //复制链表节点,并嵌入原链表 RandomListNode *p1=pHead,*p2=pHead,*res; while(p1){ RandomListNode *temp=new RandomListNode(p1->label); temp->next=p1->next; p1->next=temp; if(NULL==temp->next) break; else p1=temp->next; } //复制随机指针 p1=pHead; while(p1){ p2=p1->random; p1=p1->next; p1->random=p2; p1=p1->next; } //拆分链表 p1=pHead;p2=p1->next;res=p2; while(p1&&NULL!=p2->next){ p1->next=p2->next; p1=p1->next; p2->next=p1->next; p2=p2->next; } p1->next=NULL; return res; } };
6.顺时针打印矩阵
void print(const vector<vector<int>>& matrix, const int& len1, const int& len2, const int& n, vector<int>& res) { int i, endx = len1 - 1 - n, endy = len2 - 1 - n; //从左至右存储 for (i = n;i <= endy;++i) { res.push_back(matrix[n][i]); } //从上至下存储 if (n < endx) { for (i = n + 1;i <= endx;++i) res.push_back(matrix[i][endy]); } //从右至左打印 if (n < endx&&n < endy) { for (i = endy - 1;i >= n;--i) res.push_back(matrix[endx][i]); } //从下至上打印 if (n < endx - 1 && n < endy) { for (i = endx - 1;i >= n + 1;--i) res.push_back(matrix[i][n]); } } vector<int> printMatrix(vector<vector<int>>& matrix) { vector<int> res; int len1 = matrix.size(), len2, n = 0; if (0 == len1) { return res; } else if (1 == len1) { return matrix[0]; } else { len2 = matrix[0].size(); } while (2 * n < len1 && 2 * n < len2) { print(matrix, len1, len2, n, res); ++n; } return res; }
在VS上写程序真的是很简单,各种智能提示,在其他IDE上写程序,就得时刻注意。。。结果还是不容易找到错误
7.不能用加减乘除做加法
class Solution { public: int Add(int num1, int num2) { int sum1,sum2; do{ sum1=num1^num2; sum2=(num1&num2)<<1; num1=sum1; num2=sum2; }while(num2!=0); return sum1; } };
日了够了,就不能一遍通过,左移右移竟然能犯错误。
8.翻转字符串
注意j值的变化,机试时不带调试,实在是无语啊
class Solution { public: string ReverseSentence(string str) { int len=str.length(); if(len<=1) return str; int i,j,left,right; //首先翻转整条语句 reverse(str,0,len-1); //逐个翻转单词 left=0;right=0; for(i=0;i<len;i++){ if(str[i]!=' '){ left=i; for(j=i+1;j<=len;j++){ if(str[j]==' '||str[j]=='\0'){ right=j-1; break; } } reverse(str,left,right); i=j; //从当前为空格字符运行 } } return str; } private: void reverse(string& str,int left,int right){ if(left<0||right<0||(right-left)<=0) return; char temp; while(left<right){ temp=str[left]; str[left]=str[right]; str[right]=temp; ++left; --right; } } };
9.数组在排序数组中出现的次数
class Solution { public: int GetNumberOfK(vector<int> data ,int k) { bool sign=false; int len=data.size(); if(0==len) return 0; int left=0,right=len-1,mid; //通过二分查找法先缩小搜索范围 while(left<=right){ //注意二分查找法此处是等号,否则应对只有一个元素,岂不是呵呵了 mid=(left+right)>>1; if(data[mid]==k){ sign=true;break; }else if(data[mid]<k){ left=mid+1; }else{ right=mid-1; } } if(!sign) return 0; //确保数组中包含此数据 return getlastk(data,len,k,mid,right)-getfirstk(data,k,left,mid)+1; } int getfirstk(vector<int>& data,const int& k,int left,int right){ int mid=(left+right)>>1; int midval=data[mid]; if(midval==k){ if((mid>0&&data[mid-1]!=k)||mid==0){ return mid; }else right=mid-1; }else if(midval<k){ left=mid+1; }else{ right=mid-1; } return getfirstk(data,k,left,right); } int getlastk(vector<int>& data,const int& len,const int& k,int left,int right){ int mid=(left+right)>>1; int midval=data[mid]; if(midval==k){ if((mid<len-1&&data[mid+1]!=k)||mid==len-1){ return mid; }else{ left=mid+1; } }else if(midval<k){ left=mid+1; }else{ right=mid-1; } return getlastk(data,len,k,left,right); } };
10.二叉树的下一节点(看着答案做的,还需重新做)
class Solution { public: TreeLinkNode* GetNext(TreeLinkNode* pNode) { if(NULL==pNode) return NULL; TreeLinkNode* pnext=NULL; if(pNode->right!=NULL){ TreeLinkNode *right=pNode->right; while(right->left){ right=right->left; } pnext=right; }else if(pNode->next){ TreeLinkNode *curr=pNode; TreeLinkNode *parent=curr->next; while(parent!=NULL&&curr==parent->right){ curr=parent; parent=parent->next; } pnext=parent; }else{ //父节点无右子树 } return pnext; } };
11.按行打印二叉树
运行一直出错,还是找不到错误,后续才发现少了return res;
在线测试也不会提醒这个错误的,简直对自己无语了啊。
vector<vector<int> > Print_test(BinaryTreeNode* pRoot) { vector<vector<int>> res; if (NULL == pRoot) return res; int print = 1, nextlevel = 0; BinaryTreeNode* temp; std::queue<BinaryTreeNode*> nodes; std::vector<int> tval; nodes.push(pRoot); while (nodes.size()) { temp = nodes.front(); tval.push_back(temp->m_nValue); if (temp->m_pLeft) { nodes.push(temp->m_pLeft); ++nextlevel; } if (temp->m_pRight) { nodes.push(temp->m_pRight); ++nextlevel; } nodes.pop(); --print; if (!print) { //通过队列记录数值,并在读取完一层之后进行清空 vector<int> val; for (int i = 0;i<tval.size();++i) { val.push_back(tval[i]); } tval.clear(); res.push_back(val); print = nextlevel; nextlevel = 0; } } return res; }
以后一定先写return res;
还有就是声明指针的时候一定记住初始化为NULL。
12.找最小的k个数
class Solution { public: vector<int> GetLeastNumbers_Solution(vector<int> input, int k) { int len=input.size(); if(len<k){ vector<int> res;return res; }else if(len==k){ return input; } QuickSort(input); vector<int> data; for(int i=0;i<k;++i){ data.push_back(input[i]); } return data; } void Qsort(vector<int>& data,int left,int right) { if (left < right) { //此步保证data[pivot]大于左边的元素小于右边的元素,arry[pivot]被正确安排 int pivot = partition(data, left, right); Qsort(data, left, pivot - 1); Qsort(data, pivot + 1, right); } } void QuickSort(vector<int>&data) { Qsort(data, 0, data.size() - 1); } void swap(int&a, int&b) { int t = a;a = b;b = t; } int partition(vector<int>& data,const int& start,const int& end){ int left=start,right=end; int pivot=data[left]; while(left<right){ while(left<right&&data[right]>=pivot) --right; swap(data[left],data[right]); while(left<right&&data[left]<=pivot) ++left; swap(data[left],data[right]); } return left; } };
快排必须将第一个数值作为基准,当然,你要想选取中间数值,可以将中间数值与第一个数值进行交换。
13.反转链表
class Solution { public: ListNode* ReverseList(ListNode* pHead) { if(NULL==pHead||NULL==pHead->next) return pHead; ListNode* reversehead=NULL; ListNode* prenode=NULL; ListNode* currnode=pHead; ListNode* nextnode=NULL; while(currnode){ nextnode=currnode->next; if(NULL==nextnode){ reversehead=currnode; } currnode->next=prenode; prenode=currnode; currnode=nextnode; } return reversehead; } };
14.调整数组顺序,奇数位于偶数之前
class Solution { public: void swap(int& a,int& b){ int t=a;a=b;b=t; } void reOrderArray(vector<int> &array) { int len=array.size(); if(0==len||1==len) return; int left=0,right=len-1; while(left<right){ while(left<right&&array[left]%2==1) ++left; while(left<right&&array[right]%2==0) --right; if(left<right) swap(array[left],array[right]); } } };
不过此方法会改变奇数与奇数,偶数与偶数之间的相对关系。
15.数组中出现次数超过一半的数字
class Solution { public: int MoreThanHalfNum_Solution(vector<int> numbers) { int len=numbers.size(); if(0==len) return 0; else if(1==len) return numbers[0]; else if(len<=3) return numbers[1]; int index,start=0,end=len-1; int mid=len>>1; index=partition(numbers,start,end); while(index!=mid){ if(index>mid){ end=index-1; index=partition(numbers,start,end); }else{ start=index+1; index=partition(numbers,start,end); } } if(judge(numbers,numbers[index],len)){ return numbers[index]; }else return 0; } private: void swap(int& a,int& b){ int t=a;a=b;b=t; } //此处因为调用函数确保了鲁棒性,故此处不添加相关检验 int partition(vector<int>& num,const int& start,const int& end){ int left=start,right=end,pivot=num[start]; while(left<right){ while(left<right&&num[right]>=pivot) --right; swap(num[left],num[right]); while(left<right&&num[left]<=pivot) ++left; swap(num[left],num[right]); } return left; } bool judge(vector<int>& num,const int&k,const int& len){ int i,n=0; for(i=0;i<len;i++){ if(num[i]==k){ ++n; } } return (n>len/2)?true:false; } };
此题还是犯了错误,一个是没有判断中位数究竟是不是在数组中超过一半,即先天条件满不满足。
另外一个就是数组维数为1的时候,应该返回此数字,因为明显满足条件。。。
16.二维数组的寻找
class Solution { public: bool Find(vector<vector<int> > array,int target) { int i,j,len=array.size(); //鲁棒性检查 if(0==len) return false; for(i=0;i<len;++i){ if(array[i].size()!=len) return false; } if(array[0][0]>target) return false; if(array[len-1][len-1]<target) return false; for(j=len-1;j>=0;--j){ //数据不在当前列,跳出循环 if(target<array[0][j]||target>array[len-1][j]) continue; for(i=0;i<len;++i){ if(target==array[i][j]) return true; } } return false; } };
起始这个有更为优化的方式,我是通过列去寻找,有设置while循环,缩减行和列的数值,在逐渐缩小的块状区域寻找