java数据结构与算法刷题-----LeetCode476. 数字的补数

2024-04-15 07:44

本文主要是介绍java数据结构与算法刷题-----LeetCode476. 数字的补数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完):https://blog.csdn.net/grd_java/article/details/123063846

文章目录

    • 1. 位运算:取出非前导0位标1,进行异或
    • 2. 笨办法

在这里插入图片描述

1. 位运算:取出非前导0位标1,进行异或

因为这道题考察的就是求十进制整数的有效数值位反码问题(不是原码,补码,反码那个反码。而是1变0,0变1那个反码),各大编程语言源码实现此功能的经典方法就是这个方法,所以推荐直接理解这个方法。另外还有一道题1009. 十进制整数的反码,也是和这道题完全一样的考题。

解题思路:时间复杂度O( l o g 2 l o g 2 n u m log_2{log_2{num}} log2log2num),空间复杂度O( 1 1 1)
  1. 对整数num的二进制(不操作前导0),全部取反,就是num的补数
  2. 例如5的二进制0000 0000 0000 0000 0000 0000 0000 0101,红色的0都是前导0,求补数时,是不需要取反的。
  3. 5的补数0000 0000 0000 0000 0000 0000 0000 0010,只有黄色的非前导0部分才进行取反
  4. 如果只对010操作的话,我们只需要让其每一位和1异或就可以取反,例如101 ^ 111 = 010
  5. 但是计算机中5的二进制是0000 0000 0000 0000 0000 0000 0000 0101。如果异或1111 1111 1111 1111 1111 1111 1111 1111,会得到1111 1111 1111 1111 1111 1111 1111 1010,这样的话,答案就错了
  6. 如何解决这个问题呢?如果我们能让5的二进制只异或0000 0000 0000 0000 0000 0000 0000 0111的话,就可以得到5的补数0000 0000 0000 0000 0000 0000 0000 0010

所以对于一个数num = 0000 0000 0000 0000 0000 0000 0000 0101,如何能找出只有黄色部分全1,红色部分全0的二进制串t = 0000 0000 0000 0000 0000 0000 0000 0111,就是破题的关键

而针对这个问题,有个很简单的操作方式,就是通过位移操作和或操作配合,对1,2,4,8,16,…的右移结果相或,就可以抛弃前导0,对其余位全部填充1.案例如下:下面的案例是针对32位的int型,所以只需要右移到16.如果是64位的long型,需要右移到32,依此类推。

/** 将num中非前导0的地方都填充为1 **/
//t=num:    0100 0000 0000 0000 0000 0000 0000 0101
//t>>1      0010 0000 0000 0000 0000 0000 0000 0010
//t=t|t>>1  0110 0000 0000 0000 0000 0000 0000 0111
//t>>2      0001 1000 0000 0000 0000 0000 0000 0001
//t=t|t>>2  0111 1000 0000 0000 0000 0000 0000 0111
//t>>4      0000 0111 1000 0000 0000 0000 0000 0000
//t=t|t>>4  0111 1111 1000 0000 0000 0000 0000 0111
//t>>8      0000 0000 0111 1111 1000 0000 0000 0000
//t=t|t>>8  0111 1111 1111 1111 1000 0000 0000 0111
//t>>16     0000 0000 0000 0000 0111 1111 1111 1111
//t=t|t>>16 0111 1111 1111 1111 1111 1111 1111 1111
int t = num;
t = t | (t >> 1);
t |= t >> 2;
t |= t >> 4;
t |= t >> 8;
t |= t >> 16;

有了这个,然后再进行异或操作就完成了这道题目

代码

在这里插入图片描述

class Solution {public int findComplement(int num) {/** 将num中非前导0的地方都填充为1 **///t=num:    0100 0000 0000 0000 0000 0000 0000 0101//t>>1      0010 0000 0000 0000 0000 0000 0000 0010//t=t|t>>1  0110 0000 0000 0000 0000 0000 0000 0111//t>>2      0001 1000 0000 0000 0000 0000 0000 0001//t=t|t>>2  0111 1000 0000 0000 0000 0000 0000 0111//t>>4      0000 0111 1000 0000 0000 0000 0000 0000//t=t|t>>4  0111 1111 1000 0000 0000 0000 0000 0111//t>>8      0000 0000 0111 1111 1000 0000 0000 0000//t=t|t>>8  0111 1111 1111 1111 1000 0000 0000 0111//t>>16     0000 0000 0000 0000 0111 1111 1111 1111//t=t|t>>16 0111 1111 1111 1111 1111 1111 1111 1111int t = num;t = t | (t >> 1);t |= t >> 2;t |= t >> 4;t |= t >> 8;t |= t >> 16;//num:      0100 0000 0000 0000 0000 0000 0000 0101//t:        0111 1111 1111 1111 1111 1111 1111 1111//num ^ t   0011 1111 1111 1111 1111 1111 1111 1010return num ^ t;}
}

2. 笨办法

解题思路:时间复杂度O( l o g 2 n u m log_2 num log2num),空间复杂度O( 1 1 1)
  1. 用循环位移操作,找到最高位的1,属于暴力找位置的笨办法,也是Leetcode官方题解给出的方法,毕竟是官方解法,需要同时照顾老手和新手,推荐学有余力的同学直接掌握方法1。因为这个方法2会有溢出的风险。而方法1是各大编程语言源码中也使用的方法。
  2. 然后通过-1操作,生成除了前导0,全是1的二进制串
  3. 其思路和法1一样,但是需要自己循环找最高位,然后通过-1操作得到目标二进制串。具体看代码注释
代码

在这里插入图片描述

class Solution {public int findComplement(int num) {int highbit = 0;//找到比num最高位高的,第一位。例如num = 0101的最高为是2位置的[3位置,2位置,1位置,0位置], highbit = 1000的1的位置为3位置,正好比num的最高位高一位//找这个比num最高位的1高一位的1for (int i = 1; i <= 30; ++i) {if (num >= (1 << i)) {//如果num还是比highbit大,说明没找到,继续找highbit = i;} else {//如果num比highbit小break;//找到了,跳出循环}            }//对highbit位进行 - 1,找到全是1的低位。例如二进制1000 - 1 = 0111//但是如果highbit正好30位,则会进行溢出。直接赋值0111 1111 1111 1111 1111 1111 1111 1111//如果小于30位,我们就获取其二进制,然后-1.int mask = highbit == 30 ? 0x7fffffff : (1 << (highbit + 1)) - 1;return num ^ mask;//最后进行异或操作}
}

这篇关于java数据结构与算法刷题-----LeetCode476. 数字的补数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/905235

相关文章

使用Java发送邮件到QQ邮箱的完整指南

《使用Java发送邮件到QQ邮箱的完整指南》在现代软件开发中,邮件发送功能是一个常见的需求,无论是用户注册验证、密码重置,还是系统通知,邮件都是一种重要的通信方式,本文将详细介绍如何使用Java编写程... 目录引言1. 准备工作1.1 获取QQ邮箱的SMTP授权码1.2 添加JavaMail依赖2. 实现

Java嵌套for循环优化方案分享

《Java嵌套for循环优化方案分享》介绍了Java中嵌套for循环的优化方法,包括减少循环次数、合并循环、使用更高效的数据结构、并行处理、预处理和缓存、算法优化、尽量减少对象创建以及本地变量优化,通... 目录Java 嵌套 for 循环优化方案1. 减少循环次数2. 合并循环3. 使用更高效的数据结构4

java两个List的交集,并集方式

《java两个List的交集,并集方式》文章主要介绍了Java中两个List的交集和并集的处理方法,推荐使用Apache的CollectionUtils工具类,因为它简单且不会改变原有集合,同时,文章... 目录Java两个List的交集,并集方法一方法二方法三总结java两个List的交集,并集方法一

Spring AI集成DeepSeek三步搞定Java智能应用的详细过程

《SpringAI集成DeepSeek三步搞定Java智能应用的详细过程》本文介绍了如何使用SpringAI集成DeepSeek,一个国内顶尖的多模态大模型,SpringAI提供了一套统一的接口,简... 目录DeepSeek 介绍Spring AI 是什么?Spring AI 的主要功能包括1、环境准备2

Spring AI集成DeepSeek实现流式输出的操作方法

《SpringAI集成DeepSeek实现流式输出的操作方法》本文介绍了如何在SpringBoot中使用Sse(Server-SentEvents)技术实现流式输出,后端使用SpringMVC中的S... 目录一、后端代码二、前端代码三、运行项目小天有话说题外话参考资料前面一篇文章我们实现了《Spring

Spring AI与DeepSeek实战一之快速打造智能对话应用

《SpringAI与DeepSeek实战一之快速打造智能对话应用》本文详细介绍了如何通过SpringAI框架集成DeepSeek大模型,实现普通对话和流式对话功能,步骤包括申请API-KEY、项目搭... 目录一、概述二、申请DeepSeek的API-KEY三、项目搭建3.1. 开发环境要求3.2. mav

Springboot的自动配置是什么及注意事项

《Springboot的自动配置是什么及注意事项》SpringBoot的自动配置(Auto-configuration)是指框架根据项目的依赖和应用程序的环境自动配置Spring应用上下文中的Bean... 目录核心概念:自动配置的关键特点:自动配置工作原理:示例:需要注意的点1.默认配置可能不适合所有场景

使用Apache POI在Java中实现Excel单元格的合并

《使用ApachePOI在Java中实现Excel单元格的合并》在日常工作中,Excel是一个不可或缺的工具,尤其是在处理大量数据时,本文将介绍如何使用ApachePOI库在Java中实现Excel... 目录工具类介绍工具类代码调用示例依赖配置总结在日常工作中,Excel 是一个不可或缺的工http://

Java8需要知道的4个函数式接口简单教程

《Java8需要知道的4个函数式接口简单教程》:本文主要介绍Java8中引入的函数式接口,包括Consumer、Supplier、Predicate和Function,以及它们的用法和特点,文中... 目录什么是函数是接口?Consumer接口定义核心特点注意事项常见用法1.基本用法2.结合andThen链

spring @EventListener 事件与监听的示例详解

《spring@EventListener事件与监听的示例详解》本文介绍了自定义Spring事件和监听器的方法,包括如何发布事件、监听事件以及如何处理异步事件,通过示例代码和日志,展示了事件的顺序... 目录1、自定义Application Event2、自定义监听3、测试4、源代码5、其他5.1 顺序执行