【剑指offer】题集(缓慢更新中)

04. 二维数组中的查找

最初思路,矩阵二分。如果(mh,ml)的值大于target,那么(mh,ml)为左上角,(bh,bl)为右下角的矩阵内肯定没有target。小于target的判断方式同理。这个思路刷出来的最好用时16 ms(97.00%),内存12.6 MB(83.88%)(全靠刷)。复杂度是

class Solution {
public:
    bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
        int h = matrix.size();
        if(h == 0) return false;
        int l = matrix[0].size();
        return binary2(matrix, 0, h-1, 0, l-1, target);
    }
    bool binary2(vector<vector<int>>& matrix, int sh, int bh, int sl, int bl, int target){
        if(sh > bh || sl > bl) return false;
        if(target < matrix[sh][sl] || target > matrix[bh][bl]) return false;
        int mh = (sh + bh) >> 1;
        int ml = (sl + bl) >> 1;
        if(matrix[mh][ml] == target) return true;
        if(matrix[mh][ml] > target){
            return binary2(matrix, sh, mh-1, sl, ml-1, target) | 
                binary2(matrix, mh, bh, sl, ml-1, target) |
                binary2(matrix, sh, mh-1, ml, bl, target);
        }
        else if(matrix[mh][ml] < target){
            return binary2(matrix, mh+1, bh, ml+1, bl, target) |
                binary2(matrix, mh+1, bh, sl, ml, target) |
                binary2(matrix, sh, mh, ml+1, bl, target);
        }
        return false;
    }
};

感觉题解思路更好,从右上角开始走,正左边的数都小于自身,正下方的数都大于自身。因此可以二分的走。复杂度是 O ( m a x ( n , m ) ) O(max(n,m)) O(max(n,m))

class Solution {
public:
    bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
        int h = matrix.size();
        if(h == 0) return false;
        int l = matrix[0].size() - 1;
        int ch = 0;
        while(ch < h && l >= 0){
            if(matrix[ch][l] > target){
                l--;
            }
            else if(matrix[ch][l] < target){
                ch++;
            }
            else{
                return true;
            }
        }
        return false;
    }
};

07. 重建二叉树

已知先序中序求二叉树。用时32 ms(26.45%),内存24.4 MB(85.28%)

/**
 * 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* buildTree(vector<int>& preorder, vector<int>& inorder) {
        return build(preorder, inorder, 0, preorder.size()-1, 0, inorder.size()-1);
    }

    TreeNode* build(vector<int>& preorder, vector<int>& inorder, int pl, int pr, int il, int ir){
        if(pl > pr || il > ir) return NULL;
        //先序 pl位置是根节点
        //中序 先左子树 然后根节点 然后右子树
        TreeNode* curr = new TreeNode();
        int rt = preorder[pl];
        curr->val = rt;
        int rt_sit = il;
        while(inorder[rt_sit] != rt) rt_sit++;
        //中序 [il, rt_sit-1] [rt_sit] [rt_sit+1, ir]
        int lson = rt_sit - il;
        int rson = ir - rt_sit;
        //先序 [pl] [pl+1, pl+lson] [pl+lson+1, pr]
        curr->left = build(preorder, inorder, pl+1, pl+lson, il, rt_sit-1);
        curr->right = build(preorder, inorder, pl+lson+1, pr, rt_sit+1, ir);
        return curr;
    }
};

对时间的改进:牺牲内存,用unordered_map<int, int> mp;来记录inorder中每个数字的下标,这样就不需要枚举查询rt_sit了,直接int rt_sit = mp[preorder[pl]];

12. 矩阵中的路径

暴力dfs

const int mx = 8;
class Solution {
public:
    int op[4][2] = {{0,1}, {0,-1}, {1,0}, {-1,0}};
    int len;
    int H, L;
    bool vis[mx][mx];
    bool exist(vector<vector<char>>& board, string word) {
        H = board.size(), L = board[0].size();
        len = word.length();
        
        for(int h = 0; h < H; h++){
            for(int l = 0; l < L; l++){
                if(fun(board, h, l, 0, word)) return true;
            }
        }
        return false;
    }

    bool fun(vector<vector<char>>& board, int h, int l, int id, string word){
        if(h < 0 || h >= H || l < 0 || l >= L) return false;
        if(vis[h][l] || board[h][l] != word[id]) return false;
        if(id == len-1)return true;
        vis[h][l] = true;
        bool ok = false;
        for(int i = 0; i < 4; i++){
            ok = fun(board, h+op[i][0], l+op[i][1], id+1, word);
            if(ok) break;
        }
        vis[h][l] = false;
        return ok;
    }
};

14- I. 剪绳子

直觉告诉我凑3,如果余1就取一个3凑2x2=4。
题解:算术几何均值不等式 求导 得最佳割分为e。近似整数3。

typedef long long ll;
class Solution {
public:
    int cuttingRope(int n) {
        if(n < 5){
            if(n == 1) return 0;
            if(n == 2) return 1;
            if(n == 3) return 2;
            if(n == 4) return 4;
        }
        ll ans = 1;
        while(n >= 5){
            ans = ans * 3LL;
            n -= 3;
        }
        if(n == 4) ans *= 4;
        if(n <= 3) ans *= n;
        return ans;
    }
};

14- II. 剪绳子 II

同上,补快速幂

typedef long long ll;
const ll mod = 1e9 + 7;
class Solution {
public:
    ll ksm(ll a, ll b){
        ll ans = 1;
        while(b){
            if(b&1) ans = (ans * a) % mod;
            a = (a * a) % mod;
            b >>= 1;
        }
        return ans;
    }
    int cuttingRope(int n) {
        if(n <= 3) return n - 1;
        
        if(n % 3 == 0) return ksm(3LL, n/3);
        if(n % 3 == 2) return ksm(3LL, n/3) * 2LL % mod;
        // n % 3 == 1
        return ksm(3LL, n/3 - 1) * 4LL % mod;
    }
};

16. 数值的整数次方

快速幂,注意int范围是[-2147483647, 2147483648]。因此取负后可能超出int。

class Solution {
public:
    double ksm(double a, long long b){
        double ans = 1;
        while(b){
            if(b&1) ans = ans * a;
            a = a * a;
            b >>= 1;
        }
        return ans;
    }
    double myPow(double x, int n) {
        if(n == 0) return 1.0;
        if(n < 0) return ksm(1.0/x, (-1LL) * n);
        return ksm(x, n);
    }
};

20. 表示数值的字符串

大模拟

class Solution {
public:
    bool allNumber(string s, int l, int r){
        if(l > r) return false;//empty
        for(int i = l; i <= r; i++)
            if(s[i] < '0' || s[i] > '9') return false;
        return true;
    }
    int findCharOnly(string s, char c1, char c2, int l, int r){
        int id = -1;
        for(int i = l; i <= r; i++){
            if(s[i] == c1 || s[i] == c2){
                if(id != -1) return -2;//false
                id = i;
            }
        } 
        return id;
    }
    bool isXiaoshu(string s, int l, int r){
        if(s[l] == '-' || s[l] == '+') l++;
        int dot = findCharOnly(s, '.', '.', l, r);
        if(dot == -2) return false;//多个小数点
        if(dot == -1) return allNumber(s, l, r);//没有小数点
        bool b1 = (dot == l? true: allNumber(s, l, dot-1));
        bool b2 = (dot == r? true: allNumber(s, dot+1, r));
        //或者只有一个. 这样是不对的
        if(dot == l && dot == r) return false;
        return b1 && b2;
    }
    bool isZhengshu(string s, int l, int r){
        if(s[l] == '-' || s[l] == '+') l++;
        return allNumber(s, l, r);
    }

    bool isNumber(string s) {
        if(s.length() == 0) return false;
        int l = 0, r = s.length()-1;
        while(l <= r && s[l] == ' ') l++;
        while(l <= r && s[r] == ' ') r--;
        if(l > r) return false;
        int e = findCharOnly(s, 'e', 'E', l, r);
        if(e == -2) return false;
        if(e == -1) return isXiaoshu(s, l, r) || isZhengshu(s, l, r);
        //存在e
        bool b1 = isXiaoshu(s, l, e-1) || isZhengshu(s, l, e-1);
        bool b2 = isZhengshu(s, e+1, r);
        return b1 && b2;
    }
};

26. 树的子结构

暴力

/**
 * 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 same(TreeNode* A, TreeNode* B){
        if(A == NULL && B == NULL) return true;
        if(A != NULL && B == NULL) return true;
        if(A == NULL && B != NULL) return false;
        if(A->val != B->val) return false;
        return same(A->left, B->left) && same(A->right, B->right);
    }
    bool hasB(TreeNode *A, TreeNode *B){
        if(A == NULL) return false;
        if(same(A, B)) return true;
        return hasB(A->left, B) || hasB(A->right, B);
    }
    bool isSubStructure(TreeNode* A, TreeNode* B) {
        if(A == NULL || B == NULL) return false;
        return hasB(A, B);
    }
};

31. 栈的压入、弹出序列

验证栈的压入、弹出序列。直接模拟压入过程,如果当前栈顶是弹出序列当前值,就执行弹出。
数组实现栈占用的内存会更小

class Solution {
public:
    bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
        int num = pushed.size(), j = 0;
        int sta[num+1], head = 0;
        for(int i = 0; i < num; i++){
            sta[++head] = pushed[i];
            while(head >= 1 && sta[head] == popped[j]){
                head--;
                j++;
            }
        }
        return j == num;
    }
};

32 - I. 从上到下打印二叉树

bfs

class Solution {
public:
    vector<int> levelOrder(TreeNode* root) {
        vector<int>ans;
        queue<TreeNode*>q;
        q.push(root);
        while(!q.empty()){
            TreeNode *curr = q.front();
            q.pop();
            if(curr == NULL) continue;
            ans.push_back(curr->val);
            q.push(curr->left);
            q.push(curr->right);
        }
        return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值