剑指Offer刷题笔记

4 篇文章 0 订阅
3 篇文章 0 订阅

一、数组

剑指Offer 03.数组中重复的数字

在这里插入图片描述

思路

运用了类似桶排序的思想。因为数字在0~n-1内,于是可以将值为x的元素放在下标为x的位置,如果放置时发现数组中下标为x的元素值已经是x了,则就找到了一个重复元素。
时间复杂度O(n)
空间复杂度O(1)

代码

class Solution {
public:
    int findRepeatNumber(vector<int>& nums) {
        int i = 0;
        int N = nums.size();
        while(i<N)
        {
            if(nums[i]!=i)
            {
                int x = nums[i];
                if(nums[i]==x)
                    return x;
                swap(nums[i],nums[x]);
            }
            else i++;
        }
        return -1;
    }
};

剑指Offer 0~n-1中缺失的数字

在这里插入图片描述

思路

显然可以使用二分法。如果mid==nums[mid]则说明缺失的数字不在0~mid(含)之中,如果mid!=nums[mid]则说明缺失的数字应在mid之后的位置。
时间复杂度O(logn),空间复杂度O(1)。

代码

class Solution {
public:
    int missingNumber(vector<int>& nums) {
        int le = 0;
        int ri = nums.size();
        int mid;
        while(le<ri)
        {
            mid = (le+ri)/2;
            if(nums[mid]==mid)
                le = mid + 1;
            else ri = mid;    
        }
        return le;
    }
};

剑指Offer 11.旋转数组的最小值

在这里插入图片描述

思路

旋转之后的数组实际上是两个排序的子数组。

代码

class Solution {
public:
    int findmin(vector<int>& numbers, int le, int ri)
    {
        int result = numbers[le];
        for(int i=le+1; i<=ri; i++)
            if(result > numbers[i])
                result = numbers[i];
        return result;
    }
    int minArray(vector<int>& numbers) {
        int N = numbers.size();
        int le = 0;
        int ri = N-1;
        int mid = le;
        while(numbers[le] >= numbers[ri])
        {
            if(ri-le == 1)
            {
                mid = ri;
                break;
            }
            mid = (ri+le)/2;
            if(numbers[le]==numbers[ri]&&numbers[mid]==numbers[le])
                return findmin(numbers, le, ri);
            if(numbers[mid]>=numbers[le])
                le = mid;
            else if(numbers[mid]<=numbers[ri])
                ri = mid;
        }
        return numbers[mid];

    }
};

二、二叉树

剑指 Offer. 26. 树的子结构

在这里插入图片描述

思路

theSame(TreeNode* A, TreeNode* B)

作用:判断以A为根节点的子树是否与B有相同结构。

判断B是否为空:
B为空(表明树B遍历完全)返回true;
B不为空的情况下,A为空或A节点值与B不相等,表明不匹配,返回false;
若A、B均不为空且它们的值相等则表明该节点匹配,再递归判断A的左子树与B的左子树是否有相同结构,A的右子树与B的右子树是否有相同结构

isSubStrcture(TreeNode* A, TreeNode* B)

作用:判断B是否为A的子结构
先序遍历找到A中与B根节点值相等的节点,再判断以该节点为根节点的子树是否与树B拥有相同的结构(使用theSame(A, B)判断)。

代码

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool isSubStructure(TreeNode* A, TreeNode* B) {
        if(A==NULL || B==NULL)
            return false;
        bool result = false;
        if(A->val == B->val)
            result = theSame(A, B);
        if(!result)
            result = isSubStructure(A->left, B);
        if(!result) 
            result = isSubStructure(A->right, B);
        return result;

    }
    bool theSame(TreeNode* A, TreeNode* B)
    {
        if(B == NULL)
            return true;
        if(A == NULL || A->val != B->val)
            return false;
        return theSame(A->left, B->left) && theSame(A->right, B->right);
    }
};

剑指 Offer 27. 二叉树的镜像

代码 递归

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* mirrorTree(TreeNode* root) {
        if(root == NULL)
            return NULL;
        TreeNode* tmp  = root->left;
        root->left = mirrorTree(root->right);
        root->right = mirrorTree(tmp);
        return root;
    }
};

代码 栈

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* mirrorTree(TreeNode* root) {
        if(!root)
            return root;
        stack<TreeNode*> st;
        st.push(root);
        while(!st.empty())
        {
            TreeNode* p = st.top();
            st.pop();
            if(p->left)
                st.push(p->left);
            if(p->right)
                st.push(p->right);
            TreeNode* tmp = p->left;
            p->left = p->right;
            p->right = tmp;
        }
        return root;
    }
};

剑指 Offer 27. 二叉树的镜像

代码 递归

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        if(root==NULL)
            return true;
        return judge(root->left, root->right);
    }
    bool judge(TreeNode* p, TreeNode* q)
    {
        if(p == NULL && q == NULL)
            return true;
        if(p == NULL || q == NULL)
            return false;
        if(p->val != q->val)
            return false;
        return judge(p->left, q->right) && judge(p->right, q->left);  
            
    }
};

剑指Offer 33. 二叉搜索树的后序遍历序列

代码

class Solution {
public:
    bool verify(vector<int>& postorder, int low, int high)
    {
        int root = postorder[high];
        //找到左子树部分
        int i = low;
        for(; i < high; i++)
        {
            if(postorder[i] > root)
                break;
        }
        int j = i;
        //判断“右子树”序列是否满足每个节点都大于等于根节点
        for(; j < high; j++)
        {
            if(postorder[j] < root)
                return false;
        }
        bool left = true;
        //递归判断左子树是否满足后序遍历条件
        if(i > low)
            left = verify(postorder, low, i-1);
        bool right = true;
        //递归遍历右子树是否满足后序遍历条件
        if(i < high)
            right = verify(postorder, i, high-1);
        return (left && right);

    }
    bool verifyPostorder(vector<int>& postorder) {
        int length = postorder.size();
        if(length==0)
            return true;
        return verify(postorder, 0, length-1);
    }
};

剑指Offer 34. 二叉树中和为某一值的路径

在这里插入图片描述
遇到一个坑点:节点值可能是负数,之前写了一句当前和大于sum提前返回的句子。

代码 回溯

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> ans;
    int s;
    void dfs(TreeNode* root, int now, vector<int>& path)
    {
        if(!root)
            return;
        path.push_back(root->val);
        now += root->val;
        if(now == s && !root->left && !root->right)
        {
            ans.push_back(path);
            path.pop_back();
            return;
        }
        dfs(root->left, now, path);
        dfs(root->right, now, path);
        path.pop_back();
    }
    vector<vector<int>> pathSum(TreeNode* root, int sum) {
        s = sum;
        vector<int> path;
        dfs(root, 0, path);
        return ans;
    }
};

剑指 Offer 36. 二叉搜索树与双向链表

在这里插入图片描述

分析

将一个二叉搜索树转化为双向链表,完成这一功能的核心是记录下中序遍历的第一个节点以及记录下当前遍历节点的前驱prev,只需将prev的right指针指向当前节点,当前节点的left指针指向prev即可。一波中序遍历之后,还需修改头结点的前驱,使其指向中序遍历的最后一个节点,修改中序遍历最后一个节点的后驱,使其指向头结点。

代码 中序遍历

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* left;
    Node* right;

    Node() {}

    Node(int _val) {
        val = _val;
        left = NULL;
        right = NULL;
    }

    Node(int _val, Node* _left, Node* _right) {
        val = _val;
        left = _left;
        right = _right;
    }
};
*/

class Solution {
public:
    Node* head = NULL;
    Node* prev = NULL;
    void inorder(Node* root)
    {
        if(root->left)
            inorder(root->left);
        if(!head)
            head = root;
        root->left = prev;
        if(prev)
            prev->right = root;
        prev = root;
        if(root->right)
            inorder(root->right);
    }
    Node* treeToDoublyList(Node* root) {
        if(!root)
            return root;
        inorder(root);
        prev->right = head;
        head->left = prev;
        Node* p = head;
        return head;
    }
};

剑指 Offer 54. 二叉搜索树的第k大节点

代码 反中序遍历

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    int ans;
    void inorder(TreeNode* p, int &k)
    {
        if(p->right)
            inorder(p->right, k);
        if(k==1)
            ans = p->val;
        k--;
        if(p->left)
            inorder(p->left, k);
    }
    int kthLargest(TreeNode* root, int k) {
        if(root==NULL||k==0)
            return -1;
        inorder(root, k);
        return ans;
    }
};

剑指 Offer 68 - I. 二叉搜索树的最近公共祖先

对于求二叉搜索树的最近公共祖先,思路很简单:
根据二叉搜索树的性质有:
(1) 若p,q都大于root,则最近公共祖先应该在root的右子树找。
(2) 若p,q都小于root,则最近公共祖先应该在root的左子树找。
(3) 若p,q在root之间,则root就是最近公共组祖先了。

C++版

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root==NULL)
            return NULL;
        int val = root->val;
        if((val>=p->val&&val<=q->val)||(val>=q->val&&val<=p->val))
            return root;
        else if(val>=p->val&&val>=q->val)
            return lowestCommonAncestor(root->left, p, q);
        else return lowestCommonAncestor(root->right, p, q);
    }
};

Java版

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null) {
            return root;
        }
        if(root.val < Math.max(p.val, q.val) && root.val > Math.min(p.val, q.val)) {
            return root;
        }
        if(p.val > root.val && q.val > root.val) {
            return lowestCommonAncestor(root.right, p, q);
        }
        if(p.val < root.val && q.val < root.val) {
            return lowestCommonAncestor(root.left, p, q);
        }
        return root;
    }
}

剑指 Offer 68 - II. 二叉树的最近公共祖先

对于普通的二叉树来说,最近公共祖先的求法:
(1) 若左子树不含p,q节点,则“最近公共祖先”应该去右子树那儿找
(2) 若右子树不含p,q节点,则“最近公共祖先”应该去左子树那儿找
(3) 若p,q分别在左右子树中,则“最近公共祖先”就是root了。

C++版

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root==NULL||root==p||root==q)
            return root;
        TreeNode* le = lowestCommonAncestor(root->left,p,q);
        TreeNode* ri = lowestCommonAncestor(root->right,p,q);
        if(le!=NULL&&ri!=NULL)
            return root;
        if(le==NULL)
            return ri;
        if(ri==NULL)
            return le;
        return NULL;
    }
};

Java版

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null) {
            return root;
        }
        if(root == p || root == q) {
            return root;
        }
        TreeNode findA = lowestCommonAncestor(root.left, p, q);
        TreeNode findB = lowestCommonAncestor(root.right, p, q);
        if(findA != null && findB != null) {
            return root;
        }
        if(findB == null) {
            return findA;
        }
        if(findA == null) {
            return findB;
        }
        return null;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值