剑指offer题目练习(二)

题目十一

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

思路:遍历数组

void reOrderArray(vector &array) {
        vector res;
        int size = array.size();
        for (int i = 0;i < size;i++){
            if (array[i]%2 ==1){
                res.push_back(array[i]);
            }
        }
        for (int i = 0;i < size;i++){
            if (array[i]%2 ==0){
                res.push_back(array[i]);
            }
        }
        array = res;
    }
题目十二

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

思路:可以假想两个指针,让指针1先走k-1步,然后指针1,2同时走,这样当指针1指向最后一个节点时,指针2刚好指向倒数第k个节点。

ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        if (pListHead == nullptr || k == 0){
            return nullptr;
        }
        
        ListNode *phead1 = pListHead;
        ListNode *phead2 = nullptr;
        for (int i = 0;i < k-1;i++){
            if (phead1->next != nullptr){
                phead1 = phead1->next;
            }else{
                return nullptr;
            }
        }
        phead2 = pListHead;
        while(phead1->next != nullptr){
            phead1 = phead1->next;
            phead2 = phead2->next;
        }
        return phead2;
    }
题目十三

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

思路:翻转链表时,我们需要设置两个临时变量,pre记录当前节点的上一个节点,next记录当前节点的下一个节点,遍历链表,将当前节电的next指针指向pre。

ListNode* ReverseList(ListNode* pHead) {
        if (pHead == nullptr){
            return nullptr;
        }
        ListNode *pNode = pHead;
        ListNode *pre = nullptr;
        ListNode *reverseHead = nullptr;
        while (pNode != nullptr){
            ListNode *next = pNode->next;
            if (next == nullptr){
                reverseHead = pNode;
            }
            pNode->next = pre;
            pre = pNode;
            pNode = next;
        }
        return reverseHead;
    }
题目十四

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

思路:可以对两个链表的每个节点值进行比较,递归进行链表的合并

ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
        if (pHead1 == nullptr){
            return pHead2;
        }
        
        if (pHead2 == nullptr){
            return pHead1;
        }
        
        ListNode *mergeListHead = nullptr;
        
        if (pHead1->val < pHead2->val){
            mergeListHead = pHead1;
            mergeListHead->next = Merge(pHead1->next,pHead2);
        }else{
            mergeListHead = pHead2;
            mergeListHead->next = Merge(pHead1,pHead2->next);
        }
        
        return mergeListHead;
    }
题目十五

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

思路:递归思想,先比较A,B的根节点是否相同,相同再去判断左右子树,不同则去A的子节点中寻找与B根节点相同的节点,重复上述步骤。

class Solution {
public:
    bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
    {
        if (pRoot1 == nullptr || pRoot2 == nullptr){
            return false;
        }
        
        bool result = false;
        
        if (pRoot1!= nullptr && pRoot2 != nullptr){
            if (pRoot1->val == pRoot2->val){
                result = doesHave(pRoot1,pRoot2);
            }
            //两树根节点不同,则遍历A的子树
            if (!result){
                result = HasSubtree(pRoot1->left,pRoot2);
            }
            if (!result){
                result = HasSubtree(pRoot1->right,pRoot2);
            }
        }
        
        return result;
    }
private:
    bool doesHave(TreeNode *proot1,TreeNode *proot2){
        //因为遍历到此时还没有return false说明确定是子树
        if (proot2 == nullptr){
            return true;
        }
        
        if (proot1 == nullptr){
            return false;
        }
        
        if (proot1->val != proot2->val){
            return false;
        }
        
        return doesHave(proot1->left,proot2->left)&&doesHave(proot1->right,proot2->right);
    }
};
题目十六

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

思路:递归操作,交换左右子树

void Mirror(TreeNode *pRoot) {
        if (pRoot == nullptr){
            return;
        }
        
        TreeNode *temp = pRoot->left;
        pRoot->left = pRoot->right;
        pRoot->right = temp;
       
        if (pRoot->left){
            Mirror(pRoot->left);
        }
        
        if (pRoot->right){
            Mirror(pRoot->right);
        }
    }
题目十七

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下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.

思路:设置上下左右四个变量,控制当前打印的坐标,从外到里进行打印,注意控制条件的判断

vector printMatrix(vector > matrix) {
        int rows = matrix.size();
        int cols = matrix[0].size();
        vector res;
        if (rows == 0 && cols == 0){
            return res;
        }
        int left = 0;
        int right = cols-1;
        int top = 0;
        int btm = rows-1;
        
        while (left <= right && top <= btm){
            //从左往右打印
            for (int i = left;i <= right;i++){
                res.push_back(matrix[top][i]);
            }
            //从上往下打印
            if (top < btm){
                for (int i = top+1;i <= btm;i++){
                    res.push_back(matrix[i][right]);
                }
            }
            //从右往左打印,一定要多于一行不然没有打印的意义
            if (left < right&&top= left;i--){
                    res.push_back(matrix[btm][i]);
                }
            }
            //从下往上打印
            if (left < right&&top+1 top;i--){
                    res.push_back(matrix[i][left]);
                }
            }
            left++;right--;top++;btm--;
        }
        return res;
    }
题目十八

定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。
注意:保证测试中不会当栈为空的时候,对栈调用pop()或者min()或者top()方法。

思路:可以定义两个栈,一个栈就是普通的栈(mainStack),另一个的栈(minStack)我们让它的栈顶始终保持为最小数字,如果新push的数字小于minStack的top,则同时push到两个栈中,在pop的时候要注意,如果mainStack中把当前最小的数pop掉了,要同时将minStack的top也pop掉。

class Solution {
public:
    void push(int value) {
        if (minStk.empty()||value < minStk.top()){
            minStk.push(value);
        }
        mainStk.push(value);
    }
    void pop() {
        if (mainStk.top() == minStk.top()){
            minStk.pop();
        }
        mainStk.pop();
    }
    int top() {
        return mainStk.top();
    }
    int min() {
        return minStk.top();
    }
private:
    stack mainStk;
    stack minStk;
};
题目十九

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)

思路:这个问题我们需要借助一个辅助栈,根据pop的结果来模拟push的情况。

bool IsPopOrder(vector pushV,vector popV) {
        stacktemp;
        int index = 0;
        for (int i = 0;i < pushV.size();i++){
            while (temp.empty()||temp.top()!= popV[i]){
                temp.push(pushV[index++]);
                
                if (index > pushV.size()){
                    return false;
                }
            }
            temp.pop();
        }
        
        if (temp.empty()){
            return true;
        }else{
            return false;
        }
    }
题目二十

从上往下打印出二叉树的每个节点,同层节点从左至右打印

思路:从上往下打印二叉树,每一层从左往右,我们可以使用队列来暂存每一层的数据,因为它是先入先出,我们按照这个特点将节点从左到右加入队列中。

vector PrintFromTopToBottom(TreeNode* root) {
        vectorres;
        queueque;
        if (root == nullptr){
            return res;
        }
        TreeNode *temp = root;
        que.push(temp);
        while(!que.empty()){
            temp = que.front();
            res.push_back(temp->val);
            if (temp->left != nullptr){
                que.push(temp->left);
            }
            if (temp->right != nullptr){
                que.push(temp->right);
            }
            que.pop();
        }
        return res;
    }

你可能感兴趣的:(剑指offer题目练习(二))