算法复健-第三天
本文最后更新于 208 天前,如有失效或谬误请评论区留言。

算法复健-第三天

Math-Easy-丢失的数字

题面

给定一个包含 [0, n]n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数

示例 1:

输入:nums = [3,0,1]
输出:2
解释:n = 3,因为有 3 个数字,所以所有的数字都在范围 [0,3] 内。2 是丢失的数字,因为它没有出现在 nums 中。

示例 2:

输入:nums = [0,1]
输出:2
解释:n = 2,因为有 2 个数字,所以所有的数字都在范围 [0,2] 内。2 是丢失的数字,因为它没有出现在 nums 中。

示例 3:

输入:nums = [9,6,4,2,3,5,7,0,1]
输出:8
解释:n = 9,因为有 9 个数字,所以所有的数字都在范围 [0,9] 内。8 是丢失的数字,因为它没有出现在 nums 中。

示例 4:

输入:nums = [0]
输出:1
解释:n = 1,因为有 1 个数字,所以所有的数字都在范围 [0,1] 内。1 是丢失的数字,因为它没有出现在 nums中。

提示:

  • n == nums.length
  • 1 <= n <= 10^4
  • 0 <= nums[i] <= n
  • nums 中的所有数字都 独一无二

解答过程

本题第一眼可以打个暴力,即先对数组排序后再遍历整个数组,若某个数与其下标不相等,则得出结果,但是显然这个效率极低

为了改进上面的思路,我们可以选择使用哈希表,利用哈希表查找时间复杂度为常数的特性优化代码,总体思路和上面差不多,若最终没有找到重复的数字,则答案为n

发现时间还是有点长,想到可以使用位运算,众所不周知,按位异或是个非常神奇的东西(下面会补充按位异或的性质),我们可以在原数组后面加一个[0,n]的数组,然后对整个数组按位异或,最终得到的结果就是答案

代码

int missingNumber(vector<int>& nums) {
        // 使用哈希表的方法
        unordered_set<int> set ;
        int n = nums.size();
        for (size_t i = 0; i < n; i++)
        {
            set.insert(nums[i]);
        }
        for (size_t i = 0; i <= n; i++)
        {
            if (!set.count(i))
            {
                return i;
            }
        }
        return -1;
        // 使用位运算的方法
        return -1; 
        int res = 0 , n = nums.size();
        for (size_t i = 0; i < n; i++)
        {
            res ^= nums[i];
        }
        for (size_t i = 0; i <= n; i++)
        {
            res ^= i;
        }
        return res;
    }

补充:按位异或的妙用

首先,异或的逻辑是相同则为0,不同则为1,根据他的逻辑,我们可以总结出以下三个特点:

  • 0 ^ 0 = 0 , 0 ^ 1 = 1, 0异或任何数=任何数。
  • 1 ^ 0 = 1 , 1 ^ 1 = 0 , 1异或任何数=任何数取反。
  • 任何数异或自己 = 把自己置0。

根据这三条性质,我们可以这样使用异或:

  • 使二进制数某些特定的位数翻转,例如想要把101011001的第二位和第三位翻转 ,就可以把它和000000110做按位异或运算
  • 实现两个值的交换而不必使用临时变量(注意此处两个变量若不是整数类型,可能会出现未定义的问题,因为此时交换的是内存地址,并且这样写可读性差,建议只作为学习异或特性的方法来使用),例如a=a^b,b=b^a,a=a^b就完成了a和b的交换
  • 如同本题的,如果将一串数连续异或,由异或运算的可交换性不难得出,出现次数为偶数次的数将消失,最终结果为出现次数为奇数次的所有数的异或

Math-Easy-有效的完全平方数

题面

给你一个正整数 num 。如果 num 是一个完全平方数,则返回 true ,否则返回 false

完全平方数 是一个可以写成某个整数的平方的整数。换句话说,它可以写成某个整数和自身的乘积。

不能使用任何内置的库函数,如 sqrt

示例 1:

输入:num = 16
输出:true
解释:返回 true ,因为 4 * 4 = 16 且 4 是一个整数。

示例 2:

输入:num = 14
输出:false
解释:返回 false ,因为 3.742 * 3.742 = 14 但 3.742 不是一个整数。

提示:

  • 1 <= num <= 2^31 - 1

解答过程

本题当然可以暴力搜索,优化则使用二分搜索优化,没什么好说的

也可以使用数学方法(牛顿迭代法等)解决

代码

bool isPerfectSquare(int num) {
        long l = 1 , r = num ;
        while (l <= r)
        {
            int mid = (l + r) / 2;
            long long sq = (long)mid * mid;
            if (sq > num)
            {
                r = mid - 1;
            }
            else if (sq < num)
            {
                l = mid + 1;
            }
            else
            {
                return true;
            }

        }
        return false;
    }

Math-Easy-排列硬币

题面

你总共有 n 枚硬币,并计划将它们按阶梯状排列。对于一个由 k 行组成的阶梯,其第 i 行必须正好有 i 枚硬币。阶梯的最后一行 可能 是不完整的。

给你一个数字 n ,计算并返回可形成 完整阶梯行 的总行数。

示例 1:

img

输入:n = 5
输出:2
解释:因为第三行不完整,所以返回 2 。

示例 2:

img

输入:n = 8
输出:3
解释:因为第四行不完整,所以返回 3 。

提示:

  • 1 <= n <= 2^31 - 1

解答过程

本题当然当然也可以直接打一个暴力,优化也还是还是二分

本题也可以用数学方法解答,等差数列公式即可,小学数学题

代码

int arrangeCoins(int n) {
        int left = 1, right = n;
        while (left < right) {
            int mid = (right - left + 1) / 2 + left;
            if ((long long) mid * (mid + 1) <= (long long) 2 * n) {
                left = mid;
            } else {
                right = mid - 1;
            }
        }
        return left;   
    }
以上仅代表个人观点,如有不当之处,欢迎与我进行讨论
版权声明:除特殊说明,博客文章均为Mareep原创,依据CC BY-SA 4.0许可证进行授权,转载请附上出处链接及本声明。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇