《剑指offer》JZ11 ~ JZ20

Posted 黑桃️

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《剑指offer》JZ11 ~ JZ20相关的知识,希望对你有一定的参考价值。


JZ11:二进制中1的个数


开始使用的不断&1,发现负数有点问题,然后学到了以下方法。

n & (n-1) 可以去除n的二进制表示中最右边的一个1,n-1可将二进制中最右边一个1变为0,其右边位的数变为1。然后再与原来的n进行&操作,1&0=0,0&1=0,所以变化的部分全部变为0.

class Solution {
public:
     int  NumberOf1(int n) {
         int ans=0;
         while(n)
         {
         	 // 去除n的二进制表示中最右边的一个1
             n=n&(n-1);
             ans++;
         }
         return ans;
     }
};

JZ12:数值的整数次方


经典的快速幂,负数次方幂的情况:先求正次方幂然后求倒数即可。例如2-2=1 / 22

class Solution {
public:
    double Power(double base, int exponent) {
        // 先用正数幂求
        int n=abs(exponent);
        double ans=1;
        while(n)
        {
            if(n&1) ans*=base;
            base*=base;
            n>>=1;
        }
        // 负数处理
        if(exponent<0) ans=1/ans;
        return ans;
    }
};

JZ13:调整数组顺序使奇数位于偶数前面


直接把奇数和偶数分离,然后把偶数放在奇数后面。没考虑什么更sao的写法

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param array int整型vector 
     * @return int整型vector
     */
    vector<int> reOrderArray(vector<int>& array) {
        // write code here
        vector<int> m,n;
        for(int i=0;i<array.size();i++)
        {
        	// 奇数和偶数分别放入不同的vector
            if(array[i]%2) m.push_back(array[i]);
            else n.push_back(array[i]);
        }
        // 把偶数放在奇数后面
        for(int i=0;i<n.size();i++)
            m.push_back(n[i]);
        return m;
    }
};

JZ14:链表中倒数最后k个结点


前后指针,让后指针先走k步,然后前后指针一起往后走,那么当后指针走完链表,前指针所指的位置正好是倒数第k个。

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param pHead ListNode类 
     * @param k int整型 
     * @return ListNode类
     */
    ListNode* FindKthToTail(ListNode* pHead, int k) {
        // write code here
        ListNode* pr = pHead;
        // 后指针先走k步
        while(k--) 
        {
            if(pr==NULL) return pr;
            pr=pr->next;
        }
        // 前后指针一起往后走,直到后指针走完,前指针就是倒数第k
        while(pr)
        {
            pr=pr->next;
            pHead=pHead->next;
        }
        return pHead;
    }
};

JZ15:反转链表


原地反转,和下面blog不同的是,该种情况应该是没有头结点的那种
相关博客

class Solution {
public:
    ListNode* ReverseList(ListNode* pHead) {
        ListNode* p = pHead;
        ListNode* q = NULL;
        ListNode* t;
        
        while(p)
        {
            t = p->next;
            p->next = q;
            q = p;
            p = t;
        }
        
        return q;
    }
};

JZ16:合并两个排序的链表


俩链表都从头开始比较,小的节点就先合并,然后指针往后移,直到某一条链表比完了,那么另一条剩下的节点(一定更大)就可以直接合并

class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {
    	// 头节点
        ListNode* head = new ListNode(-1);
        ListNode* p = head;
        ListNode* q;
        while(pHead1 && pHead2)
        {
        	// pHead2的节点小,先合并pHead2的该节点,指针后移
            if(pHead1->val >= pHead2->val) 
            {
                q = new ListNode(pHead2->val);
                pHead2 = pHead2->next;
            }
            else if(pHead1->val < pHead2->val)
            {
                q = new ListNode(pHead1->val);
                pHead1 = pHead1->next;
            }
            p->next = q;
            p = q;
        }
        // 哪条剩下就直接合并剩下的
        if(pHead1) p->next = pHead1;
        if(pHead2) p->next = pHead2;
        return head->next;
    }
};

JZ17:树的子结构


两个递归,HasSubtree遍历pRoot1的各个部分与pRoot2进行比较,pan中比较pRoot1,pRoot2是否完全一致

class Solution {
public:
    bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) {
        if(pRoot2==NULL  || pRoot1==NULL) return false; 
        // 根相同(也可以不写,pan里面也会比较),且比较为true
        if(pRoot2->val==pRoot1->val  &&  pan(pRoot1,pRoot2)) return true;
        // 走左子树和右子树
        else return HasSubtree(pRoot1->left, pRoot2) || HasSubtree(pRoot1->right, pRoot2);
        
    }
    
    // 递归比较
    bool pan(TreeNode* t1, TreeNode* t2)
    {
    	// t2都比完了(代表前面都相同)就返回true
        if(t2 == NULL) return true;
        if(t1 == NULL || t1->val!=t2->val) return false;
        return pan(t1->left,t2->left) && pan(t1->right,t2->right);
    }
};

JZ18:二叉树的镜像


递归,从上到下交换所有的左右子树

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param pRoot TreeNode类 
     * @return TreeNode类
     */
    TreeNode* Mirror(TreeNode* pRoot) {
        // write code here
        if(!pRoot) return NULL;
        // 临时节点t,交换左右子树
        TreeNode* t = pRoot->left;
        pRoot->left = pRoot->right;
        pRoot->right = t;
        // 往下走,以左右子为根继续交换左右子树
        Mirror(pRoot->left);
        Mirror(pRoot->right);
        return pRoot;
    }
};

JZ19: 顺时针打印矩阵


模拟,不断以 右下左上 的方向走,直到所有点都走完,思路不难,细节需要注意,容易出错

class Solution {
public:
    vector<int> printMatrix(vector<vector<int> > matrix) {
        vector<int> ans;
        // 记录每个点是否走过
        bool vis[100][100]={0};
        // 当前所在点(x,y)
        int x=0,y=0;
        while(1)
        {
        	// 右,未出界且未走过
            while(y+1<matrix[0].size() && !vis[x][y+1])
            {
                ans.push_back(matrix[x][y]);
                vis[x][y++]=1;
            }
            while(x+1<matrix.size() && !vis[x+1][y])
            {
                ans.push_back(matrix[x][y]);
                vis[x++][y]=1;
            }
            while(y-1>=0 && !vis[x][y-1])
            {
                ans.push_back(matrix[x][y]);
                vis[x][y--]=1;
            }
            while(x-1>=0 && !vis[x-1][y])
            {
                ans.push_back(matrix[x][y]);
                vis[x--][y]=1;
            }
            // 每次转方向前不会标记位置,所以最后一个点此时没被标记,所以是-1
            if(ans.size() == matrix.size()*matrix[0].size()-1) 
            {
            	// 放入最后一个点
                ans.push_back(matrix[x][y]);
                break;
            }
        }
        return ans;
    }
};

JZ20:包含min函数的栈


一个栈用来push,另一个用来记录每次push后栈的最小值

class Solution {
public:
    stack<int> s,m;
    
    void push(int value) {
        s.push(value);
        // 栈为空时,最小值就是刚加入的value
        if(m.empty()) m.push(value);
        else{
        	// 和栈顶(记录之前的最小值)比,看谁更小
            if(value > m.top()) m.push(m.top());
            else m.push(value);
        }
    }
    void pop() {
        m.pop();
        s.pop();
    }
    int top() {
        return s.top();
    }
    int min() {
        return m.top();
    }
};

以上是关于《剑指offer》JZ11 ~ JZ20的主要内容,如果未能解决你的问题,请参考以下文章

《剑指offer》JZ11 ~ JZ20

《剑指offer》JZ41 ~ JZ50

牛客网剑指offer专题python解答JZ1---JZ12持续刷题中

牛客网剑指offer专题python解答JZ1---JZ12持续刷题中

牛客网剑指offer专题python解答JZ1---JZ12持续刷题中

《剑指offer》JZ21 ~ JZ30