剑指offer 题目总结(上)

来源:互联网 发布:网络ip摄像头监控软件 编辑:程序博客网 时间:2024/05/13 01:49

1.反转链表

通过三个指针实现链表反转,还可以通过栈实现

 ListNode* ReverseList(ListNode* pHead) {
        if(pHead==NULL)
            return NULL;
        if(pHead->next==NULL)
            return pHead;
        ListNode* p1=pHead;
        ListNode* p2=pHead->next;
        ListNode* p3=pHead->next->next;
        while(p3){
            p2->next=p1;
            p1=p2;
            p2=p3;
            p3=p3->next;
        }
        p2->next=p1;
        pHead->next=NULL;
        return p2;
    }

2.从尾到头打印链表

 可以将链表翻转后输出,或者将链表入栈后按出栈序列输出。

还可以通过递归实现,但开销略大

 
vector<int> printListFromTailToHead(struct ListNode* head) {
vector<int> dev;
if (head != NULL){
if (head->next != NULL){
dev = printListFromTailToHead(head->next);
}
dev.push_back(head->val);
}
return dev;
}
3.链表中倒数第K个结点
可设置两个指针,第一个指针先走k步,然后第二个指针从头开始走,第一个指针走到NULL,第二个指针即为倒数第K个。
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        ListNode* slow=pListHead;
        ListNode* fast=pListHead;
        for(int i=0;i<k;++i){
            if(fast==NULL)
                return NULL;
            fast=fast->next;
        }
        while(fast!=NULL) {
            slow=slow->next;
            fast=fast->next;
        }
       return slow;
}

4.合并两个排序链表

比较两个链表中最前面的数,选择小的摘出来,然后继续比较直到两指针为空。

 ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {
        if(!pHead1&&!pHead2)
            return NULL;
        ListNode* q=(ListNode*)malloc(sizeof(ListNode));
        ListNode* head=q;
        while(pHead1&&pHead2){
            ListNode* p=(ListNode*)malloc(sizeof(ListNode));
            if(pHead1->val>pHead2->val){ 
                p->val=pHead2->val;
                pHead2=pHead2->next;
            }
            else {
                p->val=pHead1->val;
                pHead1=pHead1->next;
            }
            p->next=NULL;
            q->next=p;
            q=p;
         }
        while(pHead1){
            ListNode* p=(ListNode*)malloc(sizeof(ListNode));
            p->val=pHead1->val;
            pHead1=pHead1->next;
            p->next=NULL;
            q->next=p;
            q=p;
        }
        while(pHead2){
            ListNode* p=(ListNode*)malloc(sizeof(ListNode));
            p->val=pHead2->val;
            pHead2=pHead2->next;
            p->next=NULL;
            q->next=p;
            q=p;
        }
        return head->next;
    }

5.两个链表的第一个公共结点

可以分别遍历两个链表,并记下链表长度,让长的链表先走一个他俩的差值后再让短链表从头开始走,两指针会在交点相遇。还有一个不需要记长度的方法,两指针分别遍历两链表,当第一个指针遍历完第一个链表后转到第二个链表头部开始重新遍历,第二个指针遍历完第二个链表后从第一个链表头部开始重新遍历,则两个指针第一次相遇即为交点。

ListNode* FindFirstCommonNode(ListNode *pHead1, ListNode *pHead2) {
ListNode *p1 = pHead1;
ListNode *p2 = pHead2;
while (p1 != p2){
p1 = (p1 == NULL ? pHead2 : p1->next);
p2 = (p2 == NULL ? pHead1 : p2->next);
}
returnp1;
}
6.判断链表中是否有环,找出环的入口

设置一个快指针,一个慢指针,从头开始走,两个指针若相遇,则有环。假设两指针在P点相遇,慢指针走过的距离为直线距离S加上从环中走的距离T,设环的周长为C,假设快指针走过k圈,则快指针走过的距离则为S+T+k*C,快指针走过的距离为慢指针的两倍,则有2S+2T=S+T+k*C,所以S=(k-1)*C+C-T,所以从初始点出发的指针,和快慢指针交点P出发的指针,必然会在环的入口处相交。

 ListNode* EntryNodeOfLoop(ListNode* pHead) {
        if(!pHead||!pHead->next)
            return NULL;
        ListNode* fast=pHead;
        ListNode* slow=pHead;
        fast=fast->next->next;
        slow=slow->next;
        while(fast!=slow){
            fast=fast->next->next;
            slow=slow->next;
        }
        while(pHead!=fast) {
            pHead=pHead->next;
            fast=fast->next;
        }
        return pHead;
    }

7.删除链表中重复的结点

例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

递归实现

 ListNode* deleteDuplication(ListNode* pHead)
     {
        if (pHead==NULL)
            return NULL;
        if (pHead!=NULL && pHead->next==NULL)
            return pHead;
                 
        ListNode* current;
         
        if ( pHead->next->val==pHead->val){
            current=pHead->next->next;
            while (current != NULL && current->val==pHead->val)
                current=current->next;
            return deleteDuplication(current);                     
        }
         
        else {
            current=pHead->next;
            pHead->next=deleteDuplication(current);
            return pHead;
        }    
     }

8.复杂链表的复制

每个链表结点多了一个指向任意结点的random指针

RandomListNode* Clone(RandomListNode* pHead)
    {
        if(pHead==NULL)
            return NULL;
        RandomListNode* Head=new RandomListNode(pHead->label);
        Head->random=pHead->random;
        RandomListNode* p=Head;
        pHead=pHead->next;
        while(pHead){
            RandomListNode* q=new RandomListNode(pHead->label);
            q->random=pHead->random;
            p->next=q;
            p=q;
            pHead=pHead->next;
        }
        return Head;
    }

9.二维数组的查找

在向下递增,向右递增的二维数组中查找一个数,从左下角开始向上找,target比这个数小则向上找,大则向右找

 bool Find(int target, vector<vector<int> > array) {
      for(int i=array.size()-1,j=0;i>=0&&j<array[0].size();){
          if(target==array[i][j]){
              return true;
          }
          if(target<array[i][j]){
              i--;
              continue;
          }
          if(target>array[i][j]){
              j++;
              continue;
          }
      }
          
        return false;
    }

10.将字符串中空格替换成%20

void replaceSpace(char *str,int length) {
        char *p=str+length;
        int i=0;
        int  spacecount=0;
        for(;i<length;i++){
            if(str[i]==' '){
                spacecount++;
            }
        }
        char *p2=str+length+2*spacecount;
        for(;p>=str;p--){
            if(*p==' '){
                *(p2--)='0';
                *(p2--)='2';
                *(p2--)='%'; 
            }
            else{
                *p2=*p;
                p2--;
            }
        }
 
    }       

11.用两个栈实现一个队列

class Solution
{
public:
    void push(int node) {
        stack1.push(node);
        
    }


    int pop() {
      
        if(stack2.empty()){
            while(!stack1.empty()){
            stack2.push(stack1.top());
            stack1.pop();
            }
        }
        
            int e=stack2.top();
            stack2.pop();
         
        return e;
    }


private:
    stack<int> stack1;
    stack<int> stack2;
};

12.输出旋转数组的最小数字

数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

遍历

 int minNumberInRotateArray(vector<int> rotateArray) {
        if(rotateArray.size()==0)
            return 0;
        for(int i=0;i<rotateArray.size()-1;++i){
            if(rotateArray[i]>rotateArray[i+1])
                return rotateArray[i+1];
        }
        return rotateArray[0];
    }

二分

 int minNumberInRotateArray(vector<int> rotateArray) {
        if(rotateArray.size()==0)
            return 0;
        int low=0;
        int high=rotateArray.size()-1;
        while(low<high){    
            int mid=low+(high-low)/2;
            if(rotateArray[mid]>rotateArray[0])
                low=mid+1;
            else
                high=mid;
        }
        return rotateArray[low];
    }

13.斐波那契数列

int Fibonacci(int n) {
        int f=0;
        int g=1;
        while(n--){
           g+=f;
           f=g-f;
        }
        return f;
    }

14.跳台阶

一次可以跳一阶或者两阶

int jumpFloor(int number) {
        if(number==1)
            return 1;
        if(number==2)
            return 2;
        return jumpFloor(number-1)+jumpFloor(number-2);
    }

一次可以跳n阶

f(n)=1+f(1)+f(2)+...+f(n-2)+f(n-1);

f(n-1)=1+f(1)+f(2)+...+f(n-2);

f(n)=2f(n-1);

 int jumpFloorII(int number) {
        if(number==1) return 1;
        else if(number==2) return 2;
        else{
            return 2*jumpFloorII(number-1);
        }

 }

15.矩形覆盖

我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

同斐波那契数列和跳台阶,f(n)=f(n-1)+f(n-2)

  int rectCover(int number) {
      if(number<=0)
          return 0;
      if(number  == 1)
          return 1;
      if(number==2)
          return 2;
      return rectCover((number-1))+rectCover(number-2);
    }

16.二进制中1的个数

输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

int  NumberOf1(int n) {
       int count =0;
         while(n){
             count++;
             n=n&(n-1);

         }
         return count;
     }

4bit静态表法:计算每4位有多少个1,然后求和。

int BitCount4(unsigned int n)
{
unsigned int table[16] =
{
0, 1, 1, 2,
1, 2, 2, 3,
1, 2, 2, 3,
2, 3, 3, 4
};


unsigned int count = 0;
while (n)
{
count += table[n & 0xf];
n >>= 4;
}
return count;
}

平行算法:217为例,先通过每两位的二进制数表示1的个数,再转化为每4位,最后转化为32位数字表示的二进制中1的个数,这个方法十分巧(恶)妙(心)。

int BitCount4(unsigned int n)
{
n = (n & 0x55555555) + ((n >> 1) & 0x55555555);
n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
n = (n & 0x0f0f0f0f) + ((n >> 4) & 0x0f0f0f0f);
n = (n & 0x00ff00ff) + ((n >> 8) & 0x00ff00ff);
n = (n & 0x0000ffff) + ((n >> 16) & 0x0000ffff);


return n;
}

17.数值的整数次方

实现pow函数

double Power(double base, int exponent) {
        if (exponent > 0){
   double count=base;
   for (int i = 1; i < exponent; ++i)
   base *= count;
   return base;
   }
   if (exponent == 0)
   return 1;
   else
   {
   double count = base;
   for (int i = -1; i > exponent; --i)
   base *= count;
   return 1/base;
   }
    }

18.调整数组顺序使奇数位于偶数前面

冒泡法,前偶后奇就交换

void reOrderArray(vector<int> &array) {
for (int i = 0; i < array.size(); i++)
{
for (int j = array.size() - 1; j > i; j--)
{
if (array[j] % 2 == 1 && array[j - 1] % 2 == 0) 
{
swap(array[j], array[j - 1]);
}
}
}
}

新建两个数组,一个保存奇数,一个保存偶数后合并。或者新建一个数组,遍历原数组保存偶数至新数组,删除奇数。

void reOrderArray(vector<int> &array) {
vector<int> array_temp;
vector<int>::iterator ib1, ie1;
ib1 = array.begin();
for (; ib1 != array.end();){
if (*ib1 % 2 == 0) {
array_temp.push_back(*ib1);
ib1 = array.erase(ib1);
}
else{
ib1++;
}
}
vector<int>::iterator ib2, ie2;
ib2 = array_temp.begin();
ie2 = array_temp.end();
        for (; ib2 != ie2; ib2++){
array.push_back(*ib2);
}
}

19.顺时针打印矩阵

vector<int> printMatrix(vector<vector<int> > matrix) {
int r = matrix.size();
int c = matrix[0].size();
vector<int> result;
int left = 0;
int right = c - 1;
int top = 0;
int bottom = r - 1;
        while (left <= right&&top <= bottom){
for (int i = left; i <= right; ++i)
result.push_back(matrix[top][i]);
for (int i = top + 1; i <= bottom; ++i)
result.push_back(matrix[i][right]);
if (top != bottom)
for (int i = right - 1; i >= left; --i)
result.push_back(matrix[bottom][i]);
if (left != right)
for (int i = bottom - 1; i >= top + 1; --i)
result.push_back(matrix[i][left]);
left++; right--; top++; bottom--;
}
return result;
}

20.包含min函数的栈

class Solution {
public:
    stack<int> iStack;
    stack<int> minStack;
    void push(int value){
        iStack.push(value);
        if(minStack.empty()||value<minStack.top())
            minStack.push(value);
    }
    void pop() {
        if(iStack.top()==minStack.top())
            minStack.pop();
        iStack.pop();
    }
    int top() {
        return iStack.top();
    }
    int min() {
        return minStack.top();
    }
};

21.栈的压入弹出序列

1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。

   bool IsPopOrder(vector<int> pushV,vector<int> popV){
        if(pushV.size()==0)
            return false;
        stack<int>iStack;
        for(int i=0,j=0;i<pushV.size();){
            iStack.push(pushV[i++]);
            while(j<popV.size()&&iStack.top()==popV[j]){   
                iStack.pop();
                ++j;
            }
        }
        return iStack.empty();

    }
22.字符串的全排列
vector<string> Permutation(string str) {
        vector<string>p;
        if(str.size()==0)
            return p;
        p.push_back(str);
        while(next_permutation(str.begin(),str.end())){
            p.push_back(str);
        }
        return p;
    }

0 0
原创粉丝点击