剑指offer_知识迁移能力

剑指 Offer 53 - I. 在排序数组中查找数字 I

题目

在这里插入图片描述

代码

class Solution {
public:
    //寻找右边界
    int searchrb(vector<int>& nums, int target) {
        int sz = nums.size();
        int left = 0, right = sz - 1;
        while(left <= right) {
            int mid = left + (right - left) / 2;
            if(nums[mid] <= target) {
                left = mid + 1;
            }else  {
                right = mid - 1;
            }
        }
        return left;
    }
    int search(vector<int>& nums, int target) {
        //二分法,找到目标数字的左右边界,或者查找target和target-1的右边界
        return searchrb(nums, target) - searchrb(nums, target - 1);
    }
};

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

题目

在这里插入图片描述

代码

class Solution {
public:
    int missingNumber(vector<int>& nums) {
        //二分法
        int sz = nums.size();
        int left = 0, right = sz - 1;
        while(left <= right) {
            int mid = left + (right - left) / 2;
            if(nums[mid] == mid) {
                left = mid + 1;
            }else {
                right = mid - 1;
            }
        }
        return left;
    }
};

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

题目

在这里插入图片描述

代码

法一:中序遍历+vector存值

/**
 * 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 sz = 0;
    vector<int> walk;
    void re(TreeNode* root) {
        if(root == nullptr) {
            return;
        }
        re(root->left);
        walk.push_back(root->val);
        sz++;
        re(root->right);
    }
    int kthLargest(TreeNode* root, int k) {
        //前遍历的倒数第三个节点
        re(root);
        return walk[sz - 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 res;
    void re(TreeNode* root, int& k) {
        if(root == nullptr) {
            return;
        }
        re(root->right, k);
        k--;
        if(k == 0) {
            res = root->val;
            return ;
        }
        re(root->left, k);
    }
    int kthLargest(TreeNode* root, int k) {
        //前遍历的倒数第三个节点
        re(root, k);
        return res;
    }
};

剑指 Offer 55 - I. 二叉树的深度

题目

在这里插入图片描述

代码

/**
 * 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 dfs(TreeNode* root) {
        if(root == nullptr) {
            return 0;
        }
        int l = dfs(root->left);
        int r = dfs(root->right);
        //最大深度等于左子树和右子树深度额较大值加一
        return max(l,r) + 1;
    }
    int maxDepth(TreeNode* root) {
        //递归
        return dfs(root);
    }
};

剑指 Offer 55 - II. 平衡二叉树

题目

在这里插入图片描述

代码

方法一:

/**
 * 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 flag = true;
    int depth(TreeNode* root) {
        if(root == nullptr) {
            return 0;
        }
        int ld = depth(root->left);
        int rd = depth(root->right);
        if(ld - rd > 1 || rd - ld > 1) {
            flag = false;
        }
        return max(ld, rd) + 1;
    }
    bool isBalanced(TreeNode* root) {
        depth(root);
        return flag;
    }
};

方法二:
剪枝

/**
 * 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 depth(TreeNode* root) {
        if(root == nullptr) {
            return 0;
        }
        int ld = depth(root->left);
        if(ld == -1) {
            return -1;
        }
        int rd = depth(root->right);
        if(rd == -1) {
            return -1;
        }
        if( ld - rd > 1 || rd - ld > 1 ) {
            return -1;
        }else {
            return max(ld, rd) + 1;
        }
    }
    bool isBalanced(TreeNode* root) {
        if(depth(root) != -1) {
            return true;
        }else 
        return false;
    }
};

剑指 Offer 56 - I. 数组中数字出现的次数

题目

在这里插入图片描述

代码

class Solution {
public:
    vector<int> singleNumbers(vector<int>& nums) {
        //异或也太妙了
        int z = 0;
        for(auto num: nums) {
            //z就是两个目标数字的异或值
            z = z ^ num;
        }
        int m = 1;
        //找到z中为1的位
        while((m & z) == 0) {
            m <<= 1;
        }
        int a = 0, b = 0;
        for(auto num : nums) {
            //num & m可以把数组分为两部分,两个单独的数字一定会被分开
            if(num & m) {
                a = a ^ num;
            }else {
                b = b ^ num;
            }
        }
        return vector<int>{a, b};
    }
};

剑指 Offer 56 - I. 数组中数字出现的次数

题目

在这里插入图片描述

代码

方法:有限状态机
在这里插入图片描述
不是很懂

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int one = 0, two = 0;
        for(auto num : nums) {
            one = one ^ num & ~two;
            two = two ^ num & ~one;
        }
        return one;
    }
};

剑指 Offer 57. 和为s的两个数字

题目

在这里插入图片描述

代码

能做出来

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        int sz = nums.size() ;
        int left = 0, right = sz - 1;
        vector<int>res;
        while(left < right) {
            if(nums[left] + nums[right] == target) {
                res.push_back(nums[left]);
                res.push_back(nums[right]);
                return res;
            }else if(nums[left] + nums[right] < target) {
                left++;
            }else 
                right--;
        }
        return res;
    }
};

剑指 Offer 57 - II. 和为s的连续正数序列

题目

在这里插入图片描述

代码

class Solution {
public:
    vector<vector<int>> findContinuousSequence(int target) {
        //用滑动窗口,考虑窗口内所有值
        vector<vector<int>>res;
        //s是元素和
        int left = 1, right = 2, s = 3;
        while(left < right) {
            if(s == target) {
                vector<int>ans;
                for(int i = left; i <= right; i++) {
                    ans.push_back(i);
                }
                res.push_back(ans);
            }
            if(s >= target) {
                //左边界向右移动
                s = s - left;
                left ++;
            }else {
                //右边界向右移动
                right++;
                s = s + right;
            }
        }
     return res;
    }
};

剑指 Offer 58 - I. 翻转单词顺序

题目

在这里插入图片描述

代码

感觉不太会。。。
方法:双指针、倒序

class Solution {
public:
    string reverseWords(string s) {
        //忽略头和尾部的空格
        string res;
        int sz = s.size();
        int right = sz - 1;
        while(right >= 0) {
            //从后往前寻找第一个字符
            while(s[right] == ' ') {
                right--;
            }
            //寻找第一个空格
            int left = right;
            while(left >= 0 && s[left] != ' ' ) {
                left--;
            }
            //添加单词
            res = res + s.substr(left + 1, right - left);
            res = res + ' ';
            //继续往前找
            right = left;
        }
         //去除最后一个字符多加的空格
         if(!res.empty()) {
                res.pop_back();
            }
        return res;
    }
};

剑指 Offer 58 - II. 左旋转字符串

题目

在这里插入图片描述

代码

法一:自己写的,用时和空间消耗都很大

class Solution {
public:
    string reverseLeftWords(string s, int n) {
        //左旋n个字母,按顺序把开头的n个字母依次放到最后
        int sz = s.size() - 1;
        for(int i = 0; i < n; i++) {
            s = s + s[i];
        }
        return s.substr(n, sz + n);
    }
};

法二:两部分用substr()拼接起来

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

法三:遍历拼接加取余

class Solution {
public:
    string reverseLeftWords(string s, int n) {
        string res = string(s);
        int len = s.length();
        for(int i =0 ;i<len;++i){
            res[(i+len-n)%len]=s[i];
        }
        return res;
    }
};

剑指 Offer 59 - I. 滑动窗口的最大值

题目

代码

法一:单调队列
deque 内的元素非严格递减

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        int sz = nums.size();
        vector<int> res;
        if(sz == 0) {
            return res;
        }
        res.resize(sz - k + 1);
        deque<int>dq;
        //还未形成窗口
        for(int i = 0; i < k; i++) {
            //如果双端队列末尾的元素小于当前元素,弹出
            while(!dq.empty() && dq.back() < nums[i]) {
                dq.pop_back();
            }
            dq.push_back(nums[i]);
        }
        //已经形成窗口
        //这一步不能忘
        res[0] = dq.front();
        for(int i = k; i < sz; i++) {
            //队首元素等于被删除元素,弹出
            if(dq.front() == nums[i - k]) {
                dq.pop_front();
            }
            while(!dq.empty() && dq.back() < nums[i]) {
                dq.pop_back();
            }
            dq.push_back(nums[i]);
            res[i - k + 1] = dq.front();
        }
        return res;
    }
};

方法二:
对于「最大值」,我们可以想到一种非常合适的数据结构,那就是优先队列(堆),其中的大根堆可以帮助我们实时维护一系列元素中的最大值。

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        //优先队列,大根堆,存入数组元素及其索引
        priority_queue<pair<int, int>>pq;
        int sz = nums.size();
        vector<int> res;
        if(sz == 0) {
            return res;
        }
        for(int i = 0; i < k; i++) {
            pq.push({nums[i], i});
        }
        res.push_back({pq.top().first});
        for(int i = k; i < sz; i++) {
            pq.push({nums[i], i});
            //弹出滑出窗口的元素
            while(pq.top().second <= i - k) {
                pq.pop();
            }
            res.push_back(pq.top().first);
        }
        return res;
    }
};

剑指 Offer 59 - II. 队列的最大值

题目

在这里插入图片描述

代码

本算法基于问题的一个重要性质:当一个元素进入队列的时候,它前面所有比它小的元素就不会再对答案产生影响。
咱也不知这个均摊时间复杂度都是O(1)要怎么看

class MaxQueue {
public:
    queue<int>q;
    //双端单调队列
    deque<int>dq;
    MaxQueue() {
        
    }
    
    int max_value() {
        if(q.empty()) {
            return -1;
        }
        return dq.front();
    }
    
    void push_back(int value) {
        //弹出小于value的值
        while(!dq.empty() && dq.back() < value) {
            dq.pop_back();
        }
        dq.push_back(value);
        q.push(value);

    }
    
    int pop_front() {
         if(q.empty()) {
            return -1;
        }
        int res = q.front();
        //q队首元素要么是dq的队首元素,要么是已经被dq弹出的元素
        if(res == dq.front()) {
            dq.pop_front();
        }
        q.pop();
        return res;
    }
};

/**
 * Your MaxQueue object will be instantiated and called as such:
 * MaxQueue* obj = new MaxQueue();
 * int param_1 = obj->max_value();
 * obj->push_back(value);
 * int param_3 = obj->pop_front();
 */
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值