LeeCode 231 - daily01

有为有不为,知足知不足
锐气藏于胸,和气浮于面
才气见于事,义气施于人
— 丰子恺 ​​​

业精于勤…


题目描述:

给定一个整数,编写一个函数来判断它是否是 2 的幂次方。

Leecode 231 该题在小米公司微软公司都曾被面过。

但是该题在面试过程中,真的不容易想到最优解。不过算法是一步一步演进的,不可能一步到位。

1. 普通解法

public boolean isPowerOfTwo(int n) {
        if(n <= 0) return false;
        while(n %2 == 0){
            n = n >> 1;
        }
        return n == 1;
    }

很显然,时间复杂度为O(logN)


2. 最优解

 public boolean isPowerOfTwo(int n) {
        if (n <= 0) return false;
        return (n & (n - 1)) == 0;
    }

关键点在于:(n & (n-1) )

 public boolean isPowerOfTwo(int n) {
    if (n == 0) return false;
    return (n & (-n)) == n;

关键点在于:(n & (-n) )

3.为何最优?

对于刷题有一定经验的人,见到2立刻就会联想到位运算

二进制中除了最右边的的1,其它位置上的1都表示2.

n原码反码补码
1101
2100111
3011100101
4100011100
5101010011
3.1 知识储备
  1. 负整数是以补码形式存储的;
  2. 补码 = 反码 + 1 ;
  3. 反码 = 原码按位取反;

PS:对于原码,反码,补码不太清楚的,请自行学习了解。

思路回到这道题上,判断一个数是否是2的幂,这就需要我们找一下规律啦。在现实的面试中,面试官是会给我们一定的思考时间的。

n原码
11
210
4100
81000

我们可以发现:如果是2的幂,那么其二进制表示中有且仅有一个1,有0的话后面会跟一些0

换个写法,我们会发现更多的秘密。

n原码
100000001
200000010
400000100
800001000

这样更符号在计算机中的存储规律,同时我们也发现:1的位置总是出现在最右边

那么题目就可以转化为求最右边的1

这里想一下原码,补码之间的相同点其实就是最右边的1.

n原码补码反码原码&补码
100000001111111111111111000000001
200000010111111101111110100000010
300000011111111011111110000000010
400000100111111001111101100000100
800001000111110001111011100001000

注意观察: n & (-n) 就会保留最右边的1,同时将其它位设置为0

PS : 这里列举出3,就是为了 最后的公式:n & (-n ) == n

最方便的其实是看这个:

n原码补码
111
21010
4100100
810001000
  1. 反码 = 原码按位取反;
  2. 补码 = 反码 + 1 ;
  3. n & (-n) 会保留最右边的1,同时将其它位设置为0
  4. 我们还可以发现:2的幂的数原码 和 补码 一样

3.2 延伸解法

根据上面的条件,我们肯定会猜想:

能不能把最右边的1给消灭掉?

事在人为嘛,因为二进制减一可以将最右边的1变成0,且右边的0变为1

n原码(二进制)n-1的二进制n & (n-1)
1000000010000000000000000
2000000100000000100000000
3000000110000001000000010
4000001000000001100000000
8000010000000011100000000

我们都知道:

2的幂的数1在最右边,后面跟的全是0.

这样的话,刚好跟上面的操作是互斥操作。

我们可以就可以采用 n & (n-1) == 0 来作为判断条件。

4. 总结一下

  1. 与2相关的算法题,可以优先考虑位运算
  2. 负整数在计算机中以补码形式表示;
  3. n & (-n) 可以获取到二进制中最右边的 1,且其它位设置为 0
  4. n-1 可以将最右边的 1 设置为 0,并且将右边其它位设置为 1
  5. n & (n-1) 可以将最右边的 1 设置为 0

Good Luck ~~

### 关于 CSL-Daily 的 GitHub 项目或文档 CSL-Daily 并未在所提供的引用中被直接提及。然而,可以通过分析相关内容推测其可能涉及的技术领域以及如何查找相关信息。 #### 技术背景概述 1. **ACSL 和 Frama-C 工具** ACSL(ANSI/ISO C Specification Language)是一种用于描述C程序行为的形式化规范语言[^1]。它通常与静态分析工具如 Frama-C 结合使用,以验证代码的正确性和安全性。这表明 CSL-Daily 如果存在,可能是与此类技术相关的项目或扩展功能的一部分。 2. **JSON 配置文件的支持** 提到 CustomSkinLoader 使用了 JSON 文件作为配置方式[^2]。如果 CSL-Daily 是类似的项目,则很可能也采用现代化的设计理念,例如通过 JSON 或其他结构化的数据格式来管理设置和参数。 3. **环境变量配置提示** 在某些开发环境中,需要手动调整 `LD_LIBRARY_PATH` 来加载动态链接库[^3]。这一操作对于依赖外部库运行的应用程序尤为重要。因此,若要安装或部署 CSL-Daily,需关注是否有类似的要求。 --- ### 如何定位 CSL-Daily 的官方资源? 尽管当前无法确认具体指向哪个项目的名称 “CSL-Daily”,以下是通用方法帮助找到目标: - #### 访问潜在开发者主页 假设该项目托管在一个公共平台上(比如GitHub),可以尝试搜索关键词组合 `"CSL-Daily site:github.com"` 或者查看贡献者的个人资料页面寻找关联仓库。 - #### 查阅相关社区讨论区 开源软件常伴随活跃用户群体交流心得体验;Stack Overflow、Reddit 等地方或许存留有关此主题线索。 - #### 浏览文档站点索引 官方维护的手册往往提供详尽指南介绍特性实现细节及其应用场景实例说明——即使暂时缺乏正式发布版本仍可获取初步印象。 下面给出一段 Python 脚本示范自动化查询过程: ```python import requests def search_github_repo(repo_name): url = f"https://api.github.com/search/repositories?q={repo_name}" response = requests.get(url) if response.status_code == 200: data = response.json() total_count = data['total_count'] if total_count > 0: first_result = data['items'][0] repo_url = first_result['html_url'] description = first_result['description'] return { 'url': repo_url, 'description': description } else: return None else: raise Exception(f"Failed to fetch results, status code {response.status_code}") result = search_github_repo('CSL-Daily') if result is not None: print(f"Found repository at {result['url']} with description '{result['description']}'") else: print("No matching repositories found.") ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值