剑指刷题2--C++

11.二进制中1的个数

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

解题思路:

如果一个整数不为0,那么这个整数至少有一位是1。如果我们把这个整数减1,那么原来处在整数最右边的1就会变为0,原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响.

举例 : 60 111100

​ 59 111011

​ count 1 60 & 59 = 111000

​ count 2 111000&(111000-1)=111000&(110111)=110000

​ count 3 110000&101111=100000

​ count 4 100000&011111=000000 end

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

12.数值的整数次方

给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。

保证base和exponent不同时为0

解题思路:

考虑 exponent 在0处的影响

使用快速幂算法 加速运算 使用三目运算符输出

在C语言中,power%2==1可以用更快的“位运算”来代替,例如:power&1。因为如果power为偶数,则其二进制表示的最后一位一定是0;如果power是奇数,则其二进制表示的最后一位一定是1。将他们分别与1的二进制做“与”运算,得到的就是power二进制最后一位的数字了,是0则为偶数,是1则为奇数。例如5是奇数,则5&1=1;而6是偶数,则6&1=0;因此奇偶数的判断就可以用“位运算”来替换了

同样,对于power=power/2来说,也可以用更快的“位运算”进行替代,我们只要把power的二进制表示向右移动1位就能变成原来的一半了。

class Solution {
public:
    double Power(double base, int exponent) {
        int n=abs(exponent);
        double result =1.0;
        if(base==0){
            return 0.0;
        }
        if(exponent==0)
        {
            return 1.0;
        }
         while(n!=0)
         {
             if(n&1)
             {
               result*=base;
             }
           base=base*base;
            n=n>>1;
         }
        return exponent>0?result:1/result;   
    }
};

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

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

解题思路1:

借鉴插入排序的思想 设置j k两个指针 k指针计算奇数个数 j指针遍历奇数 设置循环终止条件 由于j指针比k指针快一个字节 若缺少 j-- 循环无法弹出

class Solution {
public:
    void reOrderArray(vector<int> &array) {
        int len =array.size();
        int k=0 ;//奇数个数计数 并与j组成快慢指针
        for(int i=0;i<len;i++)
        {
            if(array[i]&1==1)
            {
                int j=i;  
            while(j>k)
                {
                    swap(array[j],array[j-1]);
                    j--;
                }
                  k++;
                }
        }   
    }
}; 

解题思路2:

不使用排序 直接new一个新数组 然后遍历出奇数 并将其放入新数组 最后遍历剩下的放入新数组

class Solution {
public:
    void reOrderArray(vector<int> &array) {
        vector<int> temp;
        for(int i=0;i<array.size();i++)
        {
            if(array[i]%2==1)
            {
                temp.push_back(array[i]);
            }
        }
         for(int i=0;i<array.size();i++)
        {
            if(array[i]%2==0)
            {
                temp.push_back(array[i]);
            }
        }
        array=temp;
    }
};

14.链表中倒数第k个结点

输入一个链表,输出该链表中倒数第k个结点。

解题思路:

使用快慢指针 fast指针 先跑 k 个节点 然后 fast slow一起跑 当fast跑到尾时 slow跑到倒数第k个

class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        if(pListHead==nullptr||k<1)
        {
            return nullptr;
        }
        ListNode* slow=pListHead;
        ListNode* fast=pListHead;
        while(k>0)
        {
            if(fast==nullptr)
            {
                return nullptr;
            }
            fast=fast->next;
            k--;
        }
        while(fast!=nullptr)
        {
            fast=fast->next;
            slow=slow->next;
        }
        return slow;
    }
};

15.反转链表

输入一个链表,反转链表后,输出新链表的表头。

解题思路:

做的时候可以画图 解析

使用两个指针 一个指向头节点 一个指向下一个节点 在断开链接时需要 保存下一个节点 其实可以算作三个指针 然后整体三个指针后移

若第一个指针为头节点 则 修改方向后 需要指向nullptr

class Solution {
public:
    ListNode* ReverseList(ListNode* pHead) {
        if(pHead==nullptr||pHead->next==NULL)
        {
            return pHead;
        }
        ListNode *pcur=pHead;
        ListNode *pnext=pHead->next;
        ListNode *pnenext;
        while(pnext!=nullptr)
        {
            pnenext=pnext->next;
            pnext->next=pcur;
            if(pcur==pHead)
            {
                pcur->next=nullptr;
            }
            pcur=pnext;
            pnext=pnenext;
        }
        return pcur;
    }
};

16.合并两个排序的链表

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

解题思路:

类似于归并排序思路 利用while和递归完成merge

class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
        if(pHead1==nullptr)
        {
            return pHead2;
        }
        if(pHead2==nullptr)
        {
            return pHead1;
        }
        ListNode* newhead=nullptr;     
            if(pHead1->val<=pHead2->val)
            {
                newhead=pHead1;
               newhead->next=Merge(pHead1->next,pHead2);
            }
            else{
              newhead=pHead2;
              newhead->next=Merge(pHead1,pHead2->next);
            }
         return newhead;       
    }
};

17.树的子结构

输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

解题思路:

递归解题 思路 是先判断根节点 是否满足条件 然后 判断 左右子树是否判断条件 然后 在满足条件时 进入判断包含的函数 此时先思考 如何判断 条件为 左右节点全部相等 然后思考退出条件

class Solution {
public:
      bool istrue(TreeNode* pRoot1, TreeNode* pRoot2)
    {
        if(pRoot2==nullptr)
        {
            return true;
        }
        if(pRoot1==nullptr)
        {
            return false;
        }
        if(pRoot1->val!=pRoot2->val)
        {
            return false;
        }
        return istrue(pRoot1->left,pRoot2->left)&& istrue(pRoot1->right,pRoot2->right);
    }
    bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
    {
        bool result =false;
        if(pRoot1&&pRoot2!=nullptr)
        {
           if(pRoot1->val==pRoot2->val)
        {
           result = istrue(pRoot1,pRoot2);
        }
        if(!result)
        {
            result=HasSubtree(pRoot1->left,pRoot2);
        }
        if(!result)
        {
            result=HasSubtree(pRoot1->right,pRoot2);
        }
        }
        return result;
    }

};

18.二叉树的镜像

操作给定的二叉树,将其变换为源二叉树的镜像。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zEijsPrz-1596962618354)(C:\Users\ian\AppData\Roaming\Typora\typora-user-images\image-20200809153228481.png)]

解题思路:

递归思路 先思考结果 再思考如何写

class Solution {
public:
  void reversetree(TreeNode *pRoot)
    {
        if(pRoot==nullptr)
        {
            return ;
        }
        swap(pRoot); 
        reversetree(pRoot->left);
        reversetree(pRoot->right);
    }
   void swap(TreeNode *pRoot)
   {
       TreeNode *temp=nullptr;
       temp=pRoot->left;
       pRoot->left=pRoot->right;
       pRoot->right=temp;
   }
    void Mirror(TreeNode *pRoot) {
         reversetree(pRoot);
    }
};

19.顺时针打印矩阵

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

解题思路:

四个变量 表示矩阵四个角 注意边界 和只有一行会重复打印

class Solution {
public:
    vector<int> printMatrix(vector<vector<int> > matrix) {
    vector<int> res;
        int row=matrix.size();
        int col=matrix[0].size();
        if(row==0||col==0)
        {
            return res;
        }
        int left =0; int right =col-1;
        int top =0;  int down =row-1;
        while(left<=right&&top<=down){
        for(int i=left;i<=right;i++) 
        {
            res.push_back(matrix[top][i]);
        }
        for(int i=top+1;i<=down;i++)
        {
            res.push_back(matrix[i][right]);
        }
            if(top!=down){
                 for(int i=right-1;i>=left;i--)
        {
            res.push_back(matrix[down][i]);
        }
        }
       if(left!=right){
          for(int i=down-1;i>top;i--)
        {
            res.push_back(matrix[i][left]);
        }
       }
          left++;right--;top++;down--;  
        }
      return res;
    }
};

20.包含min函数的栈

定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。

解题思路:

使用辅助栈 ,所有元素都进入辅助栈 ,当接受最小元素,若入栈元素小于最小函数栈元素 ,则入最小函数栈 ; 弹出时,若两栈顶不一样则弹出辅助栈 否则弹出最小函数栈 top则为辅助栈顶 min则为最小函数栈顶

class Solution {
public:
    stack<int> stk;
    stack<int> stk_min;
    void push(int value) {
        stk.push(value);
        if(stk_min.empty())
        {
           stk_min.push(value); 
        }
        else{
            if(value<stk_min.top())
            {
                stk_min.push(value);
            }
        }
    }
    void pop() {
        if(stk.top()==stk_min.top())
        {
            stk_min.pop();
        }
        stk.pop();
    }
    int top() {
       return stk.top();
    }
    int min() {
        return stk_min.top();
    }
};
     
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值