《剑指Offer》C++实现-Week6

68. 0到n-1中缺失的数字

一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0到n-1之内。

在范围0到n-1的n个数字中有且只有一个数字不在该数组中,请找出这个数字。

样例
输入:[0,1,2,4]

输出:3

class Solution {
public:
    int getMissingNumber(vector<int>& nums) {
        int n = nums.size() + 1;
        int sum = (0 + n - 1) * n / 2;
        for(auto x : nums)
        {
            sum -= x;
        }
        return sum;
    }
};

69. 数组中数值和下标相等的元素

假设一个单调递增的数组里的每个元素都是整数并且是唯一的。

请编程实现一个函数找出数组中任意一个数值等于其下标的元素。

例如,在数组[-3, -1, 1, 3, 5]中,数字3和它的下标相等。

样例
输入:[-3, -1, 1, 3, 5]

输出:3
注意:如果不存在,则返回-1。

class Solution {
public:
    int getNumberSameAsIndex(vector<int>& nums) {
        int l = 0, r = nums.size() - 1;
        while(l < r)
        {
            int mid = l + r >> 1;
            if(nums[mid] - mid >= 0) r = mid;
            else l = mid + 1;
        }
        if(nums[r] == r) return r;
        return -1;
    }
};

70. 二叉搜索树的第k个结点

给定一棵二叉搜索树,请找出其中的第k小的结点。

你可以假设树和k都存在,并且1≤k≤树的总结点数。

样例
输入:root = [2, 1, 3, null, null, null, null] ,k = 3

    2
   / \
  1   3

输出:3

/**
 * 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:
    //中序遍历的第k个元素
    TreeNode *ans;
    TreeNode* kthNode(TreeNode* root, int k) {
        dfs(root, k);
        return ans;
    }
    
    void dfs(TreeNode *root, int &k)
    {
        if(!root) return;
        dfs(root->left, k);
        k --;
        if(!k) ans = root;
        else dfs(root->right, k);
    }
};

71. 二叉树的深度

输入一棵二叉树的根结点,求该树的深度。

从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

样例
输入:二叉树[8, 12, 2, null, null, 6, 4, null, null, null, null]如下图所示:

    8
   / \
  12  2
     / \
    6   4

输出:3

/**
 * 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 treeDepth(TreeNode* root) {
        if(!root) return 0;
        return max(treeDepth(root->left), treeDepth(root->right)) + 1;
    }
};

72. 平衡二叉树

输入一棵二叉树的根结点,判断该树是不是平衡二叉树。

如果某二叉树中任意结点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。

注意:

规定空树也是一棵平衡二叉树。
样例
输入:二叉树[5,7,11,null,null,12,9,null,null,null,null]如下所示,

    5
   / \
  7  11
    /  \
   12   9

输出:true

/**
 * 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 ans = true;

    bool isBalanced(TreeNode* root) {
        dfs(root);
        return ans;
    }
    
    int dfs(TreeNode *root)
    {
        if(!root) return 0;
        int left = dfs(root->left), right = dfs(root->right);
        if(abs(left - right) > 1) ans = false;
        return max(left, right) + 1;
    }
};

73. 数组中只出现一次的两个数字

一个整型数组里除了两个数字之外,其他的数字都出现了两次。

请写程序找出这两个只出现一次的数字。

你可以假设这两个数字一定存在。

样例
输入:[1,2,3,3,4,4]

输出:[1,2]

class Solution {
public:
    vector<int> findNumsAppearOnce(vector<int>& nums) {
        int sum = 0; // x ^ y
        for(auto x : nums) sum ^= x;
        int k = 0;
        while(!(sum >> k & 1)) k ++;
        int first = 0;
        for(auto x : nums)
        {
            if(x >> k & 1)
                first ^= x;
        }
        return vector<int>{first, sum ^ first};
    }
};

74. 数组中唯一只出现一次的数字

在一个数组中除了一个数字只出现一次之外,其他数字都出现了三次。

请找出那个只出现一次的数字。

你可以假设满足条件的数字一定存在。

思考题:

如果要求只使用 O(n) 的时间和额外 O(1) 的空间,该怎么做呢?
样例
输入:[1,1,1,2,2,2,3,4,4,4]

输出:3

class Solution {
public:
    int findNumberAppearingOnce(vector<int>& nums) {
        int ones = 0, twos = 0;
        for(auto x : nums)
        {
            ones = (ones ^ x) & ~twos;
            twos = (twos ^ x) & ~ones;

        }
        return ones;
    }
};

75. 和为S的两个数字

输入一个数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。

如果有多对数字的和等于s,输出任意一对即可。

你可以认为每组输入中都至少含有一组满足条件的输出。

样例
输入:[1,2,3,4] , sum=7

输出:[3,4]

class Solution {
public:
    vector<int> findNumbersWithSum(vector<int>& nums, int target) {
        for(int i = 0; i < nums.size(); i ++)
            for(int j = i; j < nums.size(); j ++)
                if(nums[i] + nums[j] == target)
                    return vector<int>{nums[i], nums[j]};
    }
};

class Solution {
public:
    vector<int> findNumbersWithSum(vector<int>& nums, int target) {
        
        unordered_set<int> hash;
        for(int i = 0; i < nums.size(); i ++)
        {
            if(hash.count(target - nums[i])) return vector<int>{target - nums[i], nums[i]};
            hash.insert(nums[i]);
        }
        return vector<int>();
    }
}; 

76. 和为S的连续正数序列

输入一个正数s,打印出所有和为s的连续正数序列(至少含有两个数)。

例如输入15,由于1+2+3+4+5=4+5+6=7+8=15,所以结果打印出3个连续序列1~5、4~6和7~8。

样例
输入:15

输出:[[1,2,3,4,5],[4,5,6],[7,8]]

class Solution {
public:
    vector<vector<int> > findContinuousSequence(int sum) {
        vector<vector<int>> res;
        for(int i = 1, j = 1, s = 1; i <= sum; i ++)
        {
            while(s < sum) s += ++ j;
            if(s == sum && j - i + 1  > 1)
            {
                vector<int>line;
                for(int k = i; k <= j; k ++) line.push_back(k);
                res.push_back(line);
            }
            s -= i;
        }
        return res;
    }
};

77. 翻转单词顺序

输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。

为简单起见,标点符号和普通字母一样处理。

例如输入字符串"I am a student.",则输出"student. a am I"。

样例
输入:“I am a student.”

输出:“student. a am I”

class Solution {
public:
    string reverseWords(string s) {
        reverse(s.begin(), s.end());
        for(int i = 0; i < s.size(); i ++)
        {
            int j = i;
            while(j < s.size() && s[j] != ' ') j ++;
            reverse(s.begin() + i, s.begin() + j);
            i = j;
        }
        return s;
    }
};

78. 左旋转字符串

字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。

请定义一个函数实现字符串左旋转操作的功能。

比如输入字符串"abcdefg"和数字2,该函数将返回左旋转2位得到的结果"cdefgab"。

注意:

数据保证n小于等于输入字符串的长度。
样例
输入:“abcdefg” , n=2

输出:“cdefgab”

class Solution {
public:
    string leftRotateString(string str, int n) {
        reverse(str.begin(), str.end());
        reverse(str.begin(), str.begin() + str.size() - n);   
        reverse(str.begin() + str.size() - n, str.end());
        return str;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值