剑指offer习题集
1.重载赋值运算符函数:(具体见代码)
//普通做法 CMyString& CMyString::operator=(const CMyString& str) { if (this == &str) return *this; delete[] m_Pdata; m_Pdata = new char[strlen(str.m_Pdata)+1]; strcpy(m_Pdata,str.m_Pdata); return *this; } //更加安全的做法,普通做法在new内存不足情况下,已经将原值delete CMyString& CMyString::operator=(const CMyString& str) { if (this != &str) { CMyString strTemp(str); char* temp = str.m_Pdata; //通过strTemp的析构函数delete掉原值 strTemp.m_Pdata = m_Pdata; m_Pdata = temp; } return *this; }
2.替换字符串中的空白字符
瞎了,做了一遍结果还是出错。。。确实要多练练
class Solution { public: //length为数组容量 void replaceSpace(char *str,int length) { if(length<=0||str==NULL) return; int i=0,n_blank=0,n_str=0,n_strlength=0; while(str[i]!='\0'){ ++n_str; if(' '==str[i]) ++n_blank; ++i; } n_strlength=n_str+n_blank*2; if(n_strlength>length) return; int n1=n_str,n2=n_strlength; while(n1>=0&&n2>n1){ if(str[n1]==' '){ str[n2--]='0'; str[n2--]='2'; str[n2--]='%'; }else{ str[n2--]=str[n1]; } --n1; } } };
3.使用两个栈模仿队列
class Solution { public: void push(int node) { stack1.push(node); } int pop() { int temp; if(stack2.size()<=0){ while(stack1.size()>0){ temp=stack1.top(); stack2.push(temp); stack1.pop(); } } if(stack2.size()<=0) return 0; temp=stack2.top(); stack2.pop(); return temp; } private: stack<int> stack1; stack<int> stack2; };
4.改进的斐波那契数列
class Solution { public: int Fibonacci(int n) { if(n<=0) return 0; if(1==n||2==n) return 1; long long n1=1,n2=1,n3=0; for(int i=2;i<n;i++){ n3=n1+n2; n1=n2; n2=n3; } return n3; } };
5.实数的整数次方
class Solution { public: double Power(double base, int exponent) { //防止0作为底数 if(equal(base,0.0)){ if(0==exponent) return 1.0; else return 0.0; } //针对0次方做的特殊处理 if(0==exponent) return 1.0; else if(1==exponent) return base; double res; bool sign=exponent<0?true:false; if(sign){ return 1.0/PowerD(base,-1*exponent); }else{ return PowerD(base,exponent); } } bool equal(const double &a,const double &b){ if(fabs(a-b)<1e-6) return true; return false; } double PowerD(double base,int exponent){ if(1==exponent) return base; else if(0==exponent) return 1.0; double res=PowerD(base,exponent/2); res*=res; if(exponent&0x01==1){ //判断是否是奇数次方 res*=base; } return res; } };
6.求链表的倒数第k个节点
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) { } };*/ class Solution { public: ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) { if(NULL==pListHead||k==0) return NULL; int i=k; ListNode *t1=pListHead,*t2=pListHead; while(i!=0&&t1!=NULL){ --i; t1=t1->next; } if(i!=0) return NULL; while(t1!=NULL){ t1=t1->next; t2=t2->next; } return t2; } };
7.包含min函数的栈
class Solution { public: void push(int value) { m_data.push(value); if(m_min.size()==0){ m_min.push(value); }else{ if(value<m_min.top()) m_min.push(value); else m_min.push(m_min.top()); } } void pop() { if(m_data.size()>0){ m_data.pop(); m_min.pop(); } } int top() { if(m_data.size()>0) return m_data.top(); } int min() { if(m_min.size()>0) return m_min.top(); } private: stack<int> m_data; stack<int> m_min; };
8.给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]。不能使用除法。
vector<int> multiply(const vector<int>& A) { int i,len=A.size(),temp=1; vector<int> res; if(len<=1) return res; res.push_back(1); for(i=1;i<len;i++){ res.push_back(res[i-1]*A[i-1]); } for(i=len-2;i>=0;i--){ temp*=A[i+1]; res[i]*=temp; } return res; }
此题没怎么注意代码的鲁棒性,后续可以补充。
9.一个链表中包含环,请找出该链表的环的入口结点。
ListNode* EntryNodeOfLoop(ListNode* pHead) { if(pHead==NULL) return NULL; //找到环中节点 ListNode *p1=MeetListNode(pHead),*p2; if(p1==NULL) return NULL; //计算链表中环的节点个数 int i,n=1; p2=p1->next; while(p2!=p1){ ++n; p2=p2->next; } //寻找链表中环的入口节点 p1=pHead;p2=pHead; for(i=0;i<n;i++){ p1=p1->next; } while(p1!=p2){ p1=p1->next; p2=p2->next; } return p1; } ListNode* MeetListNode(ListNode* pHead){ ListNode *p1=pHead->next,*p2=pHead; if(pHead==NULL||p1==NULL||p1->next==NULL) return NULL; p1=p1->next; while(p1!=p2){ p2=p2->next; p1=p1->next; if(p1->next==NULL){ return NULL; }else{ p1=p1->next; } } return p1; }
这道题有更加快捷优化的做法,后续做更新。这里只是将书本上的思路进行阐述。
10.在一个长度为n的数组里的所有数字都在0到n-1的范围内。
数组中某些数字是重复的,但不知道有几个数字是重复的。
也不知道每个数字重复几次。请找出数组中任意一个重复的数字。
例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字2或者3。
bool duplicate(int numbers[], int length, int* duplication) { if(NULL==numbers||length<=1) return NULL; int i,temp; for(i=0;i<length;i++){ //对数据的正确性进行检测 if(numbers[i]<0||numbers[i]>length-1) return NULL; } for(i=0;i<length;i++){ while(numbers[i]!=i){ if(numbers[i]==numbers[numbers[i]]){ *duplication=numbers[i]; return true; } //进行数值交换 temp=numbers[i]; numbers[i]=numbers[temp]; numbers[temp]=temp; } } return false; }
这道题还是比较绕,不能熟练掌握。
11.第一个只出现一次的字符
此题其实比较简单,但是要知道ASCII码共有256个。其实不知道也无妨,将hashtable设置较大即可。
期望于一个循环解决问题,是可以的,但是在面试的过程中,最重要的是解决题目,进而进行优化。
class Solution { public: int FirstNotRepeatingChar(string str) { int len=str.length(); if(0==len) return -1; else if(1==len){ return 0; } const int size=256; unsigned int i,hashtable[size]={0}; for(i=0;i<len;++i){ ++hashtable[str[i]]; } for(i=0;i<len;++i){ if(1==hashtable[str[i]]) return i; } return -1; } };
12.数组中只出现一次的数字
此题可以扩展范围,比如字符之类的,总之方法如果不是看书,蛮难想到的
class Solution { public: void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) { int len=data.size(); if(len<2) return; else if(2==len&&data[0]!=data[1]){ *num1=data[0]; *num2=data[1]; return; } int i,n=0,temp=data[0],res; for(i=1;i<len;i++){ temp=temp^data[i]; } //寻找二进制中初始为1数字 while(!(temp&0x01)&&(n<8*sizeof(int))){ ++n; temp=temp>>1; } *num1=0;*num2=0; for(i=0;i<len;++i){ res=(data[i]>>n)&0x01; if(res){ *num1^=data[i]; }else{ *num2^=data[i]; } } return; } };