力扣剑指offer第2版简单题

数组中重复的数字

链接: 数组中重复的数字.

  1. 先排序,再找重复值
class Solution 
{
public:
    int findRepeatNumber(vector<int>& nums) 
    {
         sort(nums.begin(),nums.end());
         for(int i = 0;i<nums.size();++i)
         {
             if(nums[i] == nums[i+1])
             {
                return nums[i];
             }
         }
         return -1; // 数组中的值在0~n-1范围,所以可以返回-1,代表没有重复值
    }
};
  1. 哈希集合
class Solution 
{
public:
    int findRepeatNumber(vector<int>& nums) 
    {
        unordered_map<int, bool> map;
        for(int num : nums) // 遍历nums,看num是否在nums里面
        {
            if(map[num]) // 如果存在,返回num
                return num;
            map[num] = true;
        }
        return -1;
    }
};

替换空格

class Solution 
{
public:
    string replaceSpace(string s) 
    {
        string str;
        for(int i = 0; i<s.size();++i)
        {
            if(s[i] == ' ')
            {
                str.append("%20");
            }
            else
            {
                str.push_back(s[i]);
            }
        }
        return str;
    }
};

从尾到头打印链表

  1. 就地逆序数组
class Solution 
{
public:
    vector<int> reversePrint(ListNode* head) 
    {
        vector<int> result;
        while (head) 
        {
            result.push_back(head->val);
            head = head->next;
        }
        int len = result.size();
        for (int i = 0; i < len / 2; i++) 
        {
            swap(result[i], result[len-i-1]);
        }
        return result;
    }
};
  1. 使用栈
class Solution 
{
public:
    vector<int> reversePrint(ListNode* head) 
    {
        vector<int> result;
        stack<int> s;// 创建一个栈
        while(head) // 先把链表都压入栈,然后再取出来
        {
            s.push(head->val);
            head = head->next;
        }
        while(!s.empty()) 
        {
            result.push_back(s.top());
            s.pop();
        }
        return result;
    }
};
  1. 反转链表,再遍历
class Solution 
{
public:
    vector<int> reversePrint(ListNode* head) 
    {
        vector<int> result; // 定义一个数组
       
        if (head == nullptr)  // 空链表
            return result;
        // 反转链表
        ListNode *curr = head->next; // 先记住头结点的下一个结点
        ListNode *temp;
        head->next = nullptr;
        while(curr)
        {
            temp = curr->next;
            curr->next = head;
            head = curr;  // 先放头
            curr = temp;
        }
        // 取出链表中的值
        while(head) 
        {
            result.push_back(head->val);
            head = head->next;
        }
        return result;
    }
};

用两个栈实现队列

  1. 维护两个栈,第一个用来插入,第二个用来删除
class CQueue 
{
    stack<int> stack1,stack2;  // 新建两个栈
public:
    CQueue()  // 用两个栈实现队列操作
    {
        while (!stack1.empty()) // 先清空栈
        {
            stack1.pop();
        }
        while (!stack2.empty()) 
        {
            stack2.pop();
        }
    }
    
    void appendTail(int value) // 入队
    {
        stack1.push(value);
    }
    
    int deleteHead() // 出队
    {
        // 如果第二个栈为空
        if (stack2.empty()) 
        {
            while (!stack1.empty()) 
            {
                stack2.push(stack1.top()); // 先将1栈的数挪到2栈里,
                stack1.pop(); // 1 栈清空
            }
        } 
        if (stack2.empty()) // 如果 2 栈还为空,有可能放进去的也是空
        {
            return -1;
        } 
        else // 挪数据完毕,开始从 2 栈里删除
        {
            int deleteItem = stack2.top();
            stack2.pop();
            return deleteItem;
        }
    }
};

斐波那契数列

  1. 动态规划,使用滚动数组节省空间
class Solution 
{
public:
    int fib(int n)
    {
        int MOD = 1000000007;
        if (n < 2) 
        {
            return n;
        }
        int p = 0, q = 0, r = 1; // p:缓冲位置,q:参与计算的值1,r: 参与计算的值2
        for (int i = 2; i <= n; ++i) 
        {
            p = q; 
            q = r; 
            r = (p + q)%MOD;
        }
        return r;
    }
};

青蛙跳台阶问题

  1. 与斐波那契数列相似,只不过斐波那契数列中,f(0) = 0,f(1) = 1,青蛙跳台,f(0) = 1, f(1) = 1
class Solution {
public:
    int numWays(int n) 
    {
        int MOD = 1000000007;
        if(n<2)
        {
            return 1;
        }
        int p = 0, q = 1, r = 1;
        for(int i = 2; i<=n; ++i)
        {
            p = q;
            q = r;
            r = (p+q)%MOD;
        }
        return r;
    }
};

旋转数组的最小数字

  1. 二分查找
    时间复杂度 O(log(n))
class Solution 
{
public:
    int minArray(vector<int>& numbers) 
    {
        int low = 0;
        int high = numbers.size() - 1;
        while(low < high)
        {
            int priot = low + (high - low) / 2;
            if(numbers[priot] < numbers[high])
            {
                high = priot;
            }
            else if(numbers[priot] > numbers[high])
            {
                low = priot + 1;
            }
            else
            {
                high -= 1;
            }
        }
        return numbers[low];
    }
};

二进制中1的个数

  1. // 循环检查二进制位
    // 思路及解法
    // 我们可以直接循环检查给定整数 n 的二进制位的每一位是否为 1。
    // 具体代码中,当检查第 i 位时,我们可以让 n 与 2^i 进行与运算,当且仅当 n 的第 i 位为 1 时,运算结果不为 0。
class Solution 
{
public:
    int hammingWeight(uint32_t n) 
    {
        int ret = 0; // 记录1的个数
        for (int i = 0; i < 32; i++) 
        {
            if (n & (1 << i)) 
            {
                ret++;
            }
        }
        return ret;
    }
};
  1. // 位运算优化
    // n & (n-1): 其运算结果恰为把n的二进制位中的最低位 1 变为 0 之后的结果
    // 在实际代码中,不断让当前的 n 与 n-1 做与运算,直到 n 变为 0。因为每次运算会使得 n 的最低位1被翻转
    // 因此运算次数相当于 n 的二进制中 1 的个数
class Solution 
{
public:
    int hammingWeight(uint32_t n) 
    {
        int ret = 0;
        while (n) 
        {
            n &= n - 1;
            ret++;
        }
        return ret;
    }
};

打印从1到最大的n位数

  1. 不考虑大数越界情况
class Solution 
{
public:
    vector<int> printNumbers(int n)
    {
        vector <int> ans;
        int end = pow (10,n); //10^n
        for (int i = 1;i < end;i++)
        {
            ans.push_back (i);
        }
        return ans;
    }
};

删除链表的节点

class Solution 
{
public:
    ListNode* deleteNode(ListNode* head, int val) 
    {
        if(head->val == val) 
        {
            return head->next;
        }
        ListNode *pre = head, *cur = head->next;
        while(cur != nullptr && cur->val != val) 
        {
            pre = cur;
            cur = cur->next;
        }
        if(cur != nullptr) 
        {
            pre->next = cur->next;
        }
        return head;
    }
};

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

class Solution 
{
public:
    vector<int> exchange(vector<int>& nums)
    {
        int i = 0, j = nums.size() - 1; // i 从左向右找奇数,j 从右向左找 偶数
        while (i < j)  // 当i == j 时跳出循环
        {
            // nums[i] & 1 等价于 nums[i] % 2,都是求余数
            while(i < j && (nums[i] & 1) == 1) // 找到奇数
            {
                i++;
            }
            while(i < j && (nums[j] & 1) == 0) // 找到偶数
            {
                j--;
            }
            swap(nums[i], nums[j]); // 二者交换
        }
        return nums;
    }
};

链表中倒数第K个节点

  1. 假设有 n 个节点,倒数第 k 个节点,相当于整数第 n-k 个节点
    顺序遍历到第 n-k 个节点,返回即可
class Solution 
{
public:
    ListNode* getKthFromEnd(ListNode* head, int k) 
    {
        int n = 0; // 链表长度
        ListNode* node = nullptr; // 定义空节点遍历链表,计算长度

        for (node = head; node; node = node->next) // 先计算出链表的长度
        {
            n++;
        }
        for (node = head; n > k; n--)
        {
            node = node->next;
        }
      
        return node;
    }
};
  1. // 双指针,快慢指针
class Solution 
{
public:
    ListNode* getKthFromEnd(ListNode* head, int k) 
    {
        ListNode* fast = head; // 先让快慢指针都指向头节点
        ListNode* slow = head;

        while (fast && k > 0) // 让快指针先走 k 步,slow 和 fast 刚好相差 k 
        {
            fast = fast->next;
            k--;
        }
        while (fast) // 当 fast 为空节点即遍历到链表最后节点的下一个节点时,跳出循环
        {
            fast = fast->next;
            slow = slow->next;
        }
        return slow;
    }
};

反转链表

class Solution 
{
public:
    ListNode* reverseList(ListNode* head) 
    {
        ListNode* prev = nullptr;
        ListNode* curr = head;
        while (curr) 
        {
            ListNode* next = curr->next; 
            curr->next = prev;
            prev = curr;
            curr = next;
        }
        return prev;
    }
};

合并两个排序的链表

  1. 双指针
class Solution 
{
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) 
    {
        ListNode* yummy=new ListNode(0),*cur=yummy;
        while(l1 && l2) // 任意一个链表为空时跳出循环
        {
            if(l1->val<=l2->val) // 谁小就往合并链表里
            {
                cur->next=l1;
                l1=l1->next;
            }
            else
            {
                cur->next=l2;
                l2=l2->next;
            }
            cur=cur->next;
        }       
        if(l1)  cur->next=l1;
        if(l2)  cur->next=l2;
        return yummy->next;
    }
};

二叉树的镜像

class Solution 
{
public:
    TreeNode* mirrorTree(TreeNode* root) 
    {
        if (root == nullptr) 
        {
            return nullptr;
        }
        TreeNode* tmp = root->left; // 暂存 root 的左子节点
        root->left = mirrorTree(root->right); // 开启递归 root 的右子节点,并将返回值作为 root 的左子节点
        root->right = mirrorTree(tmp);  // 开启递归左子节点,并将返回值作为 root 的右子节点 
        return root;
    }
};

对称的二叉树

class Solution {
public:
    bool check(TreeNode *p, TreeNode *q) 
    {
        if(!p && !q) return true;  // 树为空返回true
        if(!p || !q) return false;
        return p->val == q->val && check(p->left,q->right) && check(p->right,q->left);       
    }
    bool isSymmetric(TreeNode* root) 
    {
        return check(root,root);
    }
};

顺时针打印矩阵

class Solution 
{
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) 
    {
        vector <int> ans; // 新建数组,存放输出的结果
        if(matrix.empty()) //若矩阵为空,直接返回答案
        {
            return ans; 
        }
        int u = 0; //赋值上下左右边界
        int d = matrix.size() - 1;
        int l = 0;
        int r = matrix[0].size() - 1;
        while(true)
        {
            for(int i = l; i <= r; ++i)  //向右移动直到最右
            {
                ans.push_back(matrix[u][i]);
            }
            if(++ u > d) //重新设定上边界,若上边界大于下边界,则遍历遍历完成,下同
            {
                break; 
            }
            for(int i = u; i <= d; ++i)  //向下
            {
                ans.push_back(matrix[i][r]);
            }
            if(-- r < l) //重新设定有边界
            {
                break; 
            }
            for(int i = r; i >= l; --i)//向左
            {
                 ans.push_back(matrix[d][i]); 
            }
            if(-- d < u)  //重新设定下边界
            {
                break;
            }
            for(int i = d; i >= u; --i)//向上
            {
                 ans.push_back(matrix[i][l]); 
            }
            if(++ l > r)  //重新设定左边界
            {
                break;
            }
        }
        return ans;
    }
};

包含min函数的栈

  1. 辅助栈
class MinStack {
    stack<int> x_stack;
    stack<int> min_stack;
public:
    MinStack() {
        min_stack.push(INT_MAX);
    }
    
    void push(int x) {
        x_stack.push(x);
        min_stack.push(std::min(min_stack.top(), x)); // 使用std:: ,这样才能调用系统的min函数,要不会和下面的min函数冲突
    }
    
    void pop() {
        x_stack.pop();
        min_stack.pop();
    }
    
    int top() {
        return x_stack.top();
    }
    
    int min() {
        return min_stack.top();
    }
};

从上到下打印二叉树

class Solution 
{
public:
    vector<vector<int>> levelOrder(TreeNode* root) 
    {
        /* 根据函数返回值定义存储结果的变量 */
        vector<vector<int>> result;
        /* 定义一个队列用于存储节点的数据 */
        queue<TreeNode*> que;
        /* 判空 */
        if(root != NULL) 
        {
            que.push(root);
        }

        /* 开始层序遍历 */
        while(!que.empty()) 
        {
            /* 计算队列的大小也即有多少个孩子 */
            int size = que.size();
            /* 定义一个临时vector 存储每一层 */
            vector<int> vec;
            /* 层序遍历 */
            for(int i = 0; i < size; i++) 
            {
                /* 获取第一个节点数据 */
                TreeNode* node = que.front();
                que.pop();

                vec.push_back(node->val);
                if(node->left != NULL) 
                {
                    que.push(node->left);
                }
                if(node->right != NULL)
                {
                     que.push(node->right);
                }
            }
            /* 将一层的数据保存 */
            result.push_back(vec);
        }
        return result;
    }
};

数组中出现次数超过一半的数字

  1. 排序
class Solution 
{
public:
    int majorityElement(vector<int>& nums) 
    {
        sort(nums.begin(),nums.end());
        return (nums[nums.size()/2]);
    }
};
  1. 哈希表
class Solution 
{
public:
    int majorityElement(vector<int>& nums) 
    {
        unordered_map<int, int> counts;
        int majority = 0, cnt = 0;
        for (int num: nums) // 遍历数组
        {
            ++counts[num];
            if (counts[num] > cnt) 
            {
                majority = num;
                cnt = counts[num];
            }
        }
        return majority;
    }
};

最小的K个数

  1. 函数自带的排序,再将最小的K个数输出
class Solution {
public:
    vector<int> getLeastNumbers(vector<int>& arr, int k) 
    {
        vector<int> nums;        
        sort(arr.begin(),arr.end());
        // for(int i = 0;i<k;++i)
        // {
        //     nums.push_back(arr[i]);
        // }
        nums.assign(arr.begin(),arr.begin()+k); // 将arr从begin--begin+k的数拷贝给nums
      
        return nums;
    }
};
  1. 快速排序
class Solution 
{
public:
    vector<int> getLeastNumbers(vector<int>& arr, int k) 
    {
        quickSort(arr, 0, arr.size() - 1);
        vector<int> res;
        res.assign(arr.begin(), arr.begin() + k);
        return res;
    }
private:
    void quickSort(vector<int>& arr, int l, int r) 
    {
        // 子数组长度为 1 时终止递归
        if (l >= r) return;
        // 哨兵划分操作(以 arr[l] 作为基准数)
        int i = l, j = r;
        while (i < j) 
        {
            while (i < j && arr[j] >= arr[l]) j--;
            while (i < j && arr[i] <= arr[l]) i++;
            swap(arr[i], arr[j]);
        }
        swap(arr[i], arr[l]);
        // 递归左(右)子数组执行哨兵划分
        quickSort(arr, l, i - 1);
        quickSort(arr, i + 1, r);
    }
};

连续子数组的最大和

  1. 动态规划
class Solution 
{
public:
    int maxSubArray(vector<int>& nums) 
    {
        int pre = 0; 
        int maxAns = nums[0]; // 存放最大值
        for (const auto &x: nums)  // 遍历 nums 数组
        {
            pre = max(pre + x, x); // 前 i 项和,与 第 i 项相比,取最大值
            maxAns = max(maxAns, pre); // 保存或更新已找到的最大值
        }
        return maxAns;
    }
};

第一个只出现一次的字符

  1. 哈希表
class Solution {
public:
    char firstUniqChar(string s) 
    {
        unordered_map<int, int> frequency;
        for (char ch: s) 
        {
            ++frequency[ch];
        }
        for (int i = 0; i < s.size(); ++i) 
        {
            if (frequency[s[i]] == 1) 
            {
                return s[i];
            }
        }
        return ' ';
    }
};

两个链表的第一个公共节点

  1. 双指针
class Solution 
{
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) 
    {
        if(headA == nullptr || headB == nullptr)
        {
            return nullptr;
        }
        ListNode *pA = headA, *pB = headB;
        while(pA != pB)
        {
            pA = pA == nullptr ? headB : pA->next;
            pB = pB == nullptr ? headA : pB->next;
        }
        return pA;
        
    }
};

在排序数组中查找数字,统计出现的次数

  1. // 暴力
class Solution {
public:
    int search(vector<int>& nums, int target) 
    {
        int ans = 0;
        for(int x: nums)
        {
            if(x == target)
            {
                ans++;
            }
        }
        return ans;
    }
};
  1. // 二分查找
class Solution {
public:
    int binarySearch(vector<int>& nums, int target, bool lower)
    {
        int left = 0;
        int right = (int)nums.size()-1;
        int ans = (int)nums.size(); // 用于存放返回数据的下标,初始为数组大小
        while(left <= right)
        {
            int mid = (left + right) / 2;
            // 如果 lower 为true,则查找第一个大于等于target的下标,否则查找第一个大于target下标
            if(nums[mid] > target || (lower && nums[mid] >= target))
            {
                right = mid -1;
                ans = mid;
            }
            else
            {
                left = mid + 1;
            }
        }
        return ans;

    }
    int search(vector<int>& nums, int target) 
    {
    // 如果 lower 为 true,则查找第一个大于等于 target 的下标,
    // 否则查找第一个大于 target 的下标。
        int leftIdx = binarySearch(nums,target,true);
        int rightIdx = binarySearch(nums,target,false) - 1;
        if(leftIdx<=rightIdx && rightIdx < nums.size() && nums[leftIdx] == target && nums[rightIdx] == target)
        {
            return rightIdx - leftIdx + 1;
        }       
        return 0;
    }
};

0–n-1中缺失的数字

class Solution 
{
public:
    int missingNumber(vector<int>& nums) 
    {
        // 二分法,如果中间的数num【i】不等于坐标i就说明缺失的数值在这个位置或者前面
        int left = 0, right = nums.size() - 1;
        int ans = nums.size();
        //初始化要注意,表示最后一个n-1缺失,这时候数组的坐标i都和num【i】相同
        while(left <= right) 
        {
            int mid = left + (right - left) / 2; // 这种方式可以防止溢出
            if(nums[mid] != mid) 
            {
                right = mid - 1;
                ans = mid;
            } 
            else  // nums[mid] != mid,此时 mid, left 和 right 到达同一位置
            {
                left = mid + 1;
            }
        }
        return ans;
    }
};

二叉搜索树的第K大节点

  1. // 二叉树,根节点的左节点比根节点小,根节点的右节点比根节点大
    // 二叉树的中序遍历为递增序列
    // 中序遍历(左,根,右)的倒序(右,根,左)则为递减序列,则第k大则为倒序的第K个节点
class Solution 
{
public:
    int count = 0, res = 0; // count 用来计数我们在降序的数字序列中走了几位,当走了k位时,让res等于此时的值
    int kthLargest(TreeNode* root, int k) 
    {
        inorder(root, k);
        return res;
    }
    void inorder(TreeNode* root, int k) // 中序遍历的倒序
    {
        if (!root) // 空树
        {
            return;
        }
        inorder(root -> right, k); // 右
        ++ count;
        if (count == k) 
        {
            res = root -> val;
            return;
        }
        inorder(root -> left, k); // 左
    }
};

二叉树的深度

class Solution {
public:
    int maxDepth(TreeNode* root) 
    {
        if(!root)
        {
            return 0;
        }
        return max(maxDepth(root->left), maxDepth(root->right))+1;
    }
};

平衡二叉树

class Solution {
public:
    int height(TreeNode* root)
    {
        if(root == NULL)
        {
            return 0;
        }
        int leftHeight = height(root->left);
        int rightHeight = height(root->right);
        if(leftHeight == -1 || rightHeight == -1 || abs(leftHeight - rightHeight)>1)
        {
            return -1; // 说明不是平衡二叉树
        }
        return max(leftHeight,rightHeight)+1;

    }


    bool isBalanced(TreeNode* root) 
    {
        return height(root)>=0; // 返回bool型
    }
};

和为s的两个数字

  1. // 双指针
class Solution 
{
public:
    vector<int> twoSum(vector<int>& nums, int target) 
    {
       int i = 0; // 左指针
       int j = nums.size() - 1; // 右指针
       while(i<j)
       {
           if(nums[i] + nums[j] == target)
           {
               return {nums[i],nums[j]};
           }
           else if(nums[i] +nums[j] > target)
           {
               j--;
           }
           else
           {
               i++;
           }
       }
       return {};
    }
};

翻转单词顺序

class Solution 
{
public:
    string reverseWords(string s) 
    {
        int i = s.size() - 1;
        string ans;
        while(i >= 0) // 用来遍历 s
        {
            int c = 0;
            while(i >= 0 && s[i] == ' ') // 用来遍历空格
            {
                i--;
            }
            while(i >= 0 && s[i] != ' ') // 用来遍历我们的字符
            {
                i--;
                c++;
            }
            if(c)
            {                                   // substr 返回由 i+1 开始的 c 个字符组成的字符串
                 ans += s.substr(i+1, c) + " "; // 返回一个单词,后面紧跟一个空格分隔
            }          
        }
        return ans.substr(0, ans.size()-1); // 减1是减去最后的一个空格
    }
};

左旋转字符串

class Solution {
public:
    string reverseLeftWords(string s, int n) 
    {
        return s.substr(n,s.size()) + s.substr(0,n);
    }
};

扑克牌中的顺子

  1. // 排序+遍历
class Solution 
{
public:
    bool isStraight(vector<int>& nums) 
    {
        int joker = 0; // 统计大小王数量
        sort(nums.begin(),nums.end()); // 排序
        for(int i = 0;i < 4;i++)
        {
            if(nums[i] == 0) // 统计大小王数量
            {
                joker++; 
            }
            else if(nums[i] == nums[i+1]) // 若有重复,提前返回 false
            {
                return false;
            }
        }
        return nums[4] - nums[joker] < 5; // 最大牌 - 最小牌 < 5 则可构成顺子

    }
};
  1. 哈希集合+遍历
class Solution {
public:
    bool isStraight(vector<int>& nums) 
    {
        unordered_map<int, bool> map;
        int mi = 14;
        int ma = 0;
        for(int num: nums)
        {
            if(num == 0) // 遇到大小王,跳过,进行下一次循环
                continue;
            ma = max(ma,num); // 更新最大值和最小值
            mi = min(mi,num);
            if(map[num]) // 有重复的就不是顺子
                return false;
            map[num] = true; //
        }
        return ma - mi < 5;
    }
};

圆圈中最后剩下的数字

  1. // 约瑟夫环
    // 动态规划:f(n) = (f(n-1)+m)%n
    n 个数,每次删除第m个
class Solution 
{
public:
    int lastRemaining(int n, int m) 
    {
        int x = 0; // f(1) = 0 恒成立
        for (int i = 2; i <= n; i++) 
        {
            x = (x + m) % i;
        }
        return x;
    }
};

不用加减乘除做加法

  1. // 位运算
    // 非进位和 + 进位项
    // 非进位和:a ^ b (a 异或 b) ,异或是无进位相加
    // 进位项: a & b << 1
class Solution 
{
public:
    int add(int a, int b) 
    {
        while(b != 0) // 当进位为 0 是跳出
        {
            int c = (unsigned int)(a & b) << 1; // c = 进位  ,,c++不支持负值左移,所以转化为无符号整型
            a ^= b; // a = 非进位和
            b = c;  // b = 进位
        }
        return a;

    }
};

二叉搜索树最近公共祖先

  1. // 一次遍历
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) 
    {
        TreeNode* ancestor = root; // 当前节点
        while (true) 
        {
            if (p->val < ancestor->val && q->val < ancestor->val) // p 和 q 的值都小于当前节点,p和q可能在当前节点的左子树里
            {
                ancestor = ancestor->left;
            }
            else if (p->val > ancestor->val && q->val > ancestor->val) // p 和 q 的值都大于当前节点,p 和 q 可能在当前节点的右子树里
            {
                ancestor = ancestor->right;
            }
            else // 否则,p q,要么是当前节点的左右子树,要么有一个就是当前节点
            {
                break;
            }
        }
        return ancestor;
    }
};

二叉树的最近公共祖先

  1. // 二叉树和二叉搜索树的区别:
    // 二叉搜索树中:左子树 < 根节点 < 右子树
    // 二叉树没有这个性质
class Solution 
{
public:
    TreeNode* ans;
    bool dfs(TreeNode* root, TreeNode* p, TreeNode* q) 
    {
        if (root == nullptr) 
        {
            return false;
        }
        bool lson = dfs(root->left, p, q);
        bool rson = dfs(root->right, p, q);
        if ((lson && rson) || ((root->val == p->val || root->val == q->val) && (lson || rson))) // 要么两个节点在是自己的左右子树,要么本身是两个节点其中一个,只有找到最近的公共祖先才会进入此判断
        {
            // lson && rson: 左子树和右子树均包含 p 节点或 q 节点
            // 如果左子树包含的是 p 节点,那么右子树只能包含 q 节点
            ans = root; // 返回找到最近的公共祖先
        } 
        return lson || rson || (root->val == p->val || root->val == q->val);
    }

    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) 
    {
        dfs(root, p, q);
        return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一记绝尘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值