剑指offer刷题记录(C++版本)(之二)

2019-08-27  本文已影响0人  傑jay

11.二进制中1的个数

class Solution {
public:
     int  NumberOf1(int n) {
         int count = 0;
        while(n!= 0){
            count++;
            n = n & (n - 1);
         }
        return count;
     }
};

12.数值的整数次方

class Solution {
    double power(double base, int exp) {
        if (exp == 1) return base;
        if ((exp & 1) == 0) { //判断exp奇偶只需要看最后一位是否为1
            int tmp = power(base, exp >> 1);//右移一位求半幂,采用快速幂算法
            return tmp * tmp;
        } else {
            int tmp = power(base, (exp - 1) >> 1);
            return tmp * tmp * base;
        }
    }
public:
    double Power(double base, int exp) {
        if (base == 0)
         {
            if (exp > 0) return 0;
            else if (exp == 0) return 0;
            else throw invalid_argument("Invalid input!");//0的负数幂无意义
          } 
    else {
            if (exp > 0) return power(base, exp);
            else if (exp == 0) return 1;
            else return 1 / power(base, -exp);
          }
    }
};

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

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);
        }
    }

14.链表倒数第k个节点

class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        ListNode *p, *q;
        p = q = pListHead;
        int i = 0;
        for (; p != NULL; i++) {
            if (i >= k)
                q = q->next;
            p = p->next;
        }
        if (i < k)
            return NULL;
        else
            return q;
    }
};

15.翻转链表

核心在于理解,反转链表反转的只是地址的指向改变

public:
    ListNode* ReverseList(ListNode* pHead) {
        ListNode *newHead = NULL;
        ListNode *currentHead = pHead;
        if(pHead == NULL || pHead->next == NULL){
            return pHead;
        }
 
        while(currentHead != NULL){
            ListNode *next = currentHead->next;
            currentHead->next = newHead;
            newHead = currentHead;
            currentHead = next;
        }
 
        return newHead;
    }

16.合并两个排序链表

public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
        if(pHead1 == NULL){
           return pHead2;
       }
       if(pHead2 == NULL){
           return pHead1;
       }
       if(pHead1->val <= pHead2->val){
           pHead1->next = Merge(pHead1->next, pHead2);
           return pHead1;
       }else{
           pHead2->next = Merge(pHead1, pHead2->next);
           return pHead2;
       }   
    }
  1. 非递归原理一样,只不过看起来更复杂
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
        if(!pHead1)
            return pHead2;
        if(!pHead2)
            return pHead1;
        ListNode* Head;
        ListNode* p;
        //取较小值作头结点
        if(pHead1->val<=pHead2->val){
            Head=pHead1;
            pHead1=pHead1->next;
        }
        else{
            Head=pHead2;
            pHead2=pHead2->next;
        }  
        //开始遍历合并
        p=Head;                                                   //p为合并后的链表的工作指针
        while(pHead1&&pHead2){                       //当有一个链表到结尾时,循环结束
            if(pHead1->val<=pHead2->val){          //如果链表1的结点小于链表2的结点
                p->next=pHead1;                            //取这个结点加入合并链表
                pHead1=pHead1->next;                 //链表1后移一位
                p=p->next;                                      //工作指针后移一位
            }               
            else{                                               //否则取链表2的结点
                p->next=pHead2;
                pHead2=pHead2->next;
                p=p->next;
            }                
        }
        if(pHead1 == NULL)           //链表1遍历完了
            p->next = pHead2;         //如果链表2也遍历完了,则pHead2=NULL
        if(pHead2 == NULL)            //链表2遍历完了
            p->next = pHead1;         ///如果链表1也遍历完了,则pHead1=NULL
        return Head;
    }

17.树的子结构

class Solution {
public:
    bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
    {
        bool result=false;
        if(pRoot1!=NULL&&pRoot2!=NULL)
        {
            if(pRoot1->val==pRoot2->val)  //如果两个相等,则进行匹配
                result=DoseTree1HaveTree2(pRoot1,pRoot2);
            if(!result)
                result=HasSubtree(pRoot1->left,pRoot2);
            if(!result)
                result=HasSubtree(pRoot1->right,pRoot2);
            //如果不等的话则分别递归查找其左边和右边
        }
        return result;   //如果没找到这里还是false
    }
    
    bool DoseTree1HaveTree2(TreeNode* pRoot1,TreeNode* pRoot2)
    {
        if(pRoot2==NULL)    //如果已经比遍历到pRoot2位空,那么说明是子树
            return true;
        if(pRoot1==NULL)     //如果pRoot1为空pRoot2不为空(如果为空已经返回),则说明不是子树
            return false;
        if(pRoot1->val!=pRoot2->val)  //如果存在两个值不相等,那么肯定也不是子树
            return false;
        return DoseTree1HaveTree2(pRoot1->left,pRoot2->left)&&
            DoseTree1HaveTree2(pRoot1->right,pRoot2->right);
        //剩下的就是递归得判断左右是否相等了。
    }
};

18.二叉树的镜像

class Solution {
public:
    void Mirror(TreeNode *pRoot) {
//终止条件就是当前的节点为空
        if(pRoot==NULL)   return;
        
        //交换节点
        TreeNode *tmp=new TreeNode(0);
        tmp->left=pRoot->left;
        tmp->right=pRoot->right;
        pRoot->left=tmp->right;
        pRoot->right=tmp->left;
        delete tmp;
        
        //判断左右分别是为空,不为空的话递归的来求镜像
        if(pRoot->left)
            Mirror(pRoot->left);
        if(pRoot->right)
            Mirror(pRoot->right);
    }
};

19.顺时针打印矩阵

public:
    vector<int> printMatrix(vector<vector<int> > matrix) {
        int row = matrix.size();
        int col = matrix[0].size();
        vector<int> res;
         
        // 输入的二维数组非法,返回空的数组
        if (row == 0 || col == 0)  return res;
         
        // 定义四个关键变量,表示左上和右下的打印范围
        int left = 0, top = 0, right = col - 1, bottom = row - 1;
        while (left <= right && top <= bottom)
        {
            // left to right
            for (int i = left; i <= right; ++i)  res.push_back(matrix[top][i]);
            // top to bottom
            for (int i = top + 1; i <= bottom; ++i)  res.push_back(matrix[i][right]);
            // right to left
            if (top != bottom)
            for (int i = right - 1; i >= left; --i)  res.push_back(matrix[bottom][i]);
            // bottom to top
            if (left != right)
            for (int i = bottom - 1; i > top; --i)  res.push_back(matrix[i][left]);
            left++,top++,right--,bottom--;
        }
        return res;
    }
};

20.包含min函数的栈

class Solution {
public:
    void push(int value) {
        s.push(value);
        if(sMin.empty())
            sMin.push(value);
        else if(value <= sMin.top())//进栈时比之前最小元素还小,则同时进最小值栈
            sMin.push(value);
    }
    void pop() {
        if(s.top() == sMin.top())//出栈时位当前最小元素,则最小值栈同时出
            sMin.pop();
        s.pop();
    }
    int top() {
        return s.top();
    }
    int min() {
       return sMin.top();
    }
private://定义两个栈,一个实现正常栈的功能,一个用了存最小值栈
    stack<int> s;
    stack<int> sMin;
};
上一篇 下一篇

猜你喜欢

热点阅读