LeetCode刷题笔记(3)Java位运算符与使用按位异或(进制之间的转换)
1.问题描述
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
算法应该具有线性时间复杂度并且不使用额外空间。
输入: [4,1,2,1,2]
输出: 4
2.解题思路
这道题的主要的难点是具有线性时间复杂度并且不能使用额外的空间,因此就排除了很多的方法。
当时使用双指针尝试了以下,但是并没有取得成功,因为最后的结果可能是错误的。
3.正确解题思路
使用“按位异或”,即Java中的‘^’运算符来进行计算。
由于异或的原则是,不同为1,相同为0,题目中给定的数组中,如果两个相同的数异或的结果一定为0,最后得到的结果就是只出现一次的元素。
public int singleNumber(int[] nums) {
int res = nums[0];
for (int i = 1; i < nums.length; i++) {
res ^= nums[i];
}
return res;
}
4.另外的一个例子
需要找出t中不在s中的那个字符。
输入:
s = "abcd"
t = "abcde" 输出:
e
也可以用按位异或的方式进行计算
public char findTheDifference(String s, String t) {
char c = 0;
for (int i = 0; i < s.length(); ++i) {
c ^= s.charAt(i);
}
for (int i = 0; i < t.length(); ++i) {
c ^= t.charAt(i);
}
return c;
}
5.问题描述
不使用“+”“-”运算符计算两个整数的和。
(1)自己的思路:模拟计算机实际来操作二进制数补码的加法
Integer.parseInt无法将一个负数的补码转换成原始的负数,否则会报错java.lang.NumberFormatException
此时,只能这么来计算:取反码,然后加1,转换成相反数,然后添加上一个符号“-”
// System.out.println(new e371().getSum(a, b));
System.out.println("11111111111111111111111111101100".length());
System.out.println(Integer.toBinaryString(-20));
// System.out.println(Integer.parseInt("11111111111111111111111111101100", 2));
System.out.println(Integer.parseInt("00000000000000000000000000010100", 2));
解题思路:模仿实际计算机的真实计算结果,超级麻烦!!!!!!
class Solution {
public int getSum(int a, int b) { String aStr = Integer.toBinaryString(a);
String bStr = Integer.toBinaryString(b);
String longStr = (aStr.length() < bStr.length()) ? bStr : aStr;
String shortStr = (aStr.length() < bStr.length()) ? aStr : bStr;
StringBuffer sb = new StringBuffer();
for (int i = 0; i < longStr.length() - shortStr.length(); i++) {
sb.append(0);
}
shortStr = sb.toString().concat(shortStr); boolean isUp = false;
StringBuffer resSB = new StringBuffer();
for (int i = longStr.length() - 1; i >= 0; i--) {
if (!isUp) {
if (longStr.charAt(i)== '1' && shortStr.charAt(i) == '1') {
isUp = true;
resSB.append(0);
} else {
resSB.append(Integer.valueOf(longStr.charAt(i)) ^ Integer.valueOf(shortStr.charAt(i)));
}
} else {
if (longStr.charAt(i) == '1' && shortStr.charAt(i) == '1') {
isUp = true;
resSB.append(1);
} else if (longStr.charAt(i) == '0' && shortStr.charAt(i)== '0') {
resSB.append(1);
isUp = false;
} else {
resSB.append(0);
isUp = true;
}
}
} if (isUp && resSB.length() < 32) resSB.append(1);
String result = resSB.reverse().toString();
if (result.length() < 32) {
return Integer.parseInt(result, 2);
}
if (result.charAt(0) == '0') {
return Integer.parseInt(result, 2);
} else {
StringBuffer sbsb = new StringBuffer();
for (char c : result.toCharArray()) {
if (c == '1') {
sbsb.append(0);
} else {
sbsb.append(1);
}
}
result = sbsb.toString(); longStr = result;
shortStr = "00000000000000000000000000000001"; boolean isUp_1 = false;
StringBuffer resSB_1 = new StringBuffer();
for (int i = longStr.length() - 1; i >= 0; i--) {
if (!isUp_1) {
if (longStr.charAt(i)== '1' && shortStr.charAt(i) == '1') {
isUp_1 = true;
resSB_1.append(0);
} else {
resSB_1.append(Integer.valueOf(longStr.charAt(i)) ^ Integer.valueOf(shortStr.charAt(i)));
}
} else {
if (longStr.charAt(i) == '1' && shortStr.charAt(i) == '1') {
isUp_1 = true;
resSB_1.append(1);
} else if (longStr.charAt(i) == '0' && shortStr.charAt(i)== '0') {
resSB_1.append(1);
isUp_1 = false;
} else {
resSB_1.append(0);
isUp_1 = true;
}
}
}
result = resSB_1.reverse().toString();
return -Integer.parseInt(result, 2);
}
}
}
(2)更好的思路,使用位运算符
public int getSum(int a, int b) {
if(b == 0){ //没有进位的时候完成运算
return a;
}
int sum,carry;
sum = a^b; //完成第一步加法的运算
carry = (a&b)<<1; //完成第二步进位并且左移运算
return getSum(sum,carry);//
}
根据实际例子分析这块代码:
(1)a=1,b=2
a-> 00000000 00000000 00000000 00000001
b-> 00000000 00000000 00000000 00000010
b=2
sum-> 00000000 00000000 00000000 00000011
a&b-> 00000000 00000000 00000000 00000000
carry-> 00000000 00000000 00000000 00000000 输出sum=3 (2)a=1,b=7
a-> 00000000 00000000 00000000 00000001
b-> 00000000 00000000 00000000 00000111
a&b-> 00000000 00000000 00000000 00000001
sum-> 00000000 00000000 00000000 00000110
carry-> 00000000 00000000 00000000 00000010 a&b-> 00000000 00000000 00000000 00000010
sum-> 00000000 00000000 00000000 00000100
carry-> 00000000 00000000 00000000 00000100
a&b-> 00000000 00000000 00000000 00000100
sum-> 00000000 00000000 00000000 00000000
carry-> 00000000 00000000 00000000 00001000
a&b-> 00000000 00000000 00000000 00000000
sum-> 00000000 00000000 00000000 00001000
carry-> 00000000 00000000 00000000 00000000 输出sum = 8 (3)a=-16,b=14
a-> 11111111111111111111111111110000
b-> 00000000000000000000000000001110
a&b-> 00000000000000000000000000000000
sum-> 11111111111111111111111111111110
carry-> 0 输出sum=-2
6.Java位运算符
(1)"~(按位取反)"
~(-14) == 13(int类型)
-14(原码):10000000 00000000 00000000 00001110
-14(反码):11111111 11111111 11111111 11110001
-14(补码):11111111 11111111 11111111 11110010
非过程(同时为1才为1):00000000 00000000 00000000 00001101
十进制表示为:1+4+8=13
(2)"&(按位与)"
5&-4 == 4(int类型)
-4(原码):10000000 00000000 00000000 00000100
-4(反码):11111111 11111111 11111111 11111011
-4(补码):11111111 11111111 11111111 11111100
5 : 00000000 00000000 00000000 00000101
-4: 11111111 11111111 11111111 11111100
与过程(同时为1才为1):
00000000 00000000 00000000 00000100
十进制表示为:4
(3)"|(按位或)"
3|6 == 7(int类型)
3: 00000000 00000000 00000000 00000011
6: 00000000 00000000 00000000 00000110
或过程(只要有1就为1):
00000000 00000000 00000000 00000111
十进制表示为:1+2+4=7
(4)"^(按位异或)"
10^3 == 9(int类型)
3 : 00000000 00000000 00000000 00000011
10: 00000000 00000000 00000000 00001010
异或过程(不同为1相同为0):
00000000 00000000 00000000 00001001
十进制表示为:1+8=9
(5)"<<(左移,低位添0补齐)"
-2<<3 == -16(int类型)
-2 : 11111111 11111111 11111111 11111110
<<过程:111(舍弃) 11111111 11111111 11111111 11110 000(补零)
十进制表示为:-16
(6)">>(右移,高位添符号位)"
15>>2 == 3(int类型)
15 : (符号位是0)00000000 00000000 00000000 00001111
>>过程:00(补两个0) 000000 00000000 00000000 00000011 11(舍弃最末位两个11)
十进制表示为:1+2=3
(7)">>>(右移,高位添0补齐)"
4>>>2 == 1(int类型)
4 : 00000000 00000000 00000000 00000100
>>>过程:00(补两个0) 000000 00000000 00000000 00000001 00(舍弃最末位两个00)
十进制表示为:1
LeetCode刷题笔记(3)Java位运算符与使用按位异或(进制之间的转换)的更多相关文章
- matlab学习笔记10_6 字符串与数值间的转换以及进制之间的转换
一起来学matlab-matlab学习笔记10 10_6 字符串与数值间的转换以及进制之间的转换 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考书籍 <matlab 程序设计与综合 ...
- LeetCode刷题笔记和想法(C++)
主要用于记录在LeetCode刷题的过程中学习到的一些思想和自己的想法,希望通过leetcode提升自己的编程素养 :p 高效leetcode刷题小诀窍(这只是目前对我自己而言的小方法,之后会根据自己 ...
- Java基础知识强化106:Java中 int 的各进制之间的转换
1.二.八.十.十六进制之间的转换 下面是示例代码,我们直接通过JDK工具库中的方法实现的,如下: public static Integer valueOf(String s, int radix ...
- LeetCode刷题总结-双指针、位运算和分治法篇
本文总结LeetCode上有关双指针.位运算和分治法的算法题,推荐刷题总数14道.具体考点分析如下图: 一.双指针 1.字符串和数组问题 题号:424. 替换后的最长重复字符,难度中等 题号:828. ...
- LeetCode刷题笔记 - 12. 整数转罗马数字
学好算法很重要,然后要学好算法,大量的练习是必不可少的,LeetCode是我经常去的一个刷题网站,上面的题目非常详细,各个标签的题目都有,可以整体练习,本公众号后续会带大家做一做上面的算法题. 官方链 ...
- 18.9.10 LeetCode刷题笔记
本人算法还是比较菜的,因此大部分在刷基础题,高手勿喷 选择Python进行刷题,因为坑少,所以不太想用CPP: 1.买股票的最佳时期2 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格. ...
- leetcode刷题笔记342 4的幂
题目描述: 给定一个整数 (32位有符整数型),请写出一个函数来检验它是否是4的幂. 示例:当 num = 16 时 ,返回 true . 当 num = 5时,返回 false. 问题进阶:你能不使 ...
- 【leetcode刷题笔记】Excel Sheet Column Number
Related to question Excel Sheet Column Title Given a column title as appear in an Excel sheet, retur ...
- 【leetcode刷题笔记】Best Time to Buy and Sell Stock II
Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...
随机推荐
- java自学小测试 九九乘法表
public class Ninenine { public static void main(String[] args) { for(int i=1;i<=9;i++){ for(int j ...
- 基于RHEL8/CentOS8的网络基础配置
在rhel7上,同时支持network.service和NetworkManager.service(简称NM).默认情况下,这2个服务都有开启,但许多人都会将NM禁用掉.而在rhel8上,已废弃ne ...
- 读取unicode日志文件并清除记录的垃圾文件
//读取unicode文件,并清除记录的垃圾文件 //参数1:日志文件路径 bool ReadFilePath(const wchar_t *DataFilePath) { wchar_t ChBuf ...
- Android测试环境配置
测试是软件开发中非常重要的一部分,Android中是使用junit测试框架,本文使用的是junit4和Android Studio.Android测试主要分两类本地测试和Instrumented测试, ...
- layDate——初步使用
layui系列中layDate的使用教程网址 https://www.layui.com/laydate/ 我这里简单举例: 1.引入js <script type="text/jav ...
- 深度解密Go语言之反射
目录 什么是反射 为什么要用反射 反射是如何实现的 types 和 interface 反射的基本函数 反射的三大定律 反射相关函数的使用 代码样例 未导出成员 反射的实际应用 json 序列化 De ...
- python爬虫——京东评论、jieba分词、wordcloud词云统计
接上一章,动态页面抓取——抓取京东评论区内容. url=‘https://club.jd.com/comment/productPageComments.action?callback=fetchJS ...
- 向net core 3.0进击——April.WebApi从2.2爬到3.0
目录 前言 升级之路 测试 小结 前言 在之前对Swagger的变化做了调整后,就开始想着要不把之前的工程升级得了,这样就还是个demo工程,来做各种测试(当然还是因为懒),这就有了今天这个比较折腾的 ...
- 浅谈Java的内存模型以及交互
本文的内存模型只写虚拟机内存模型,物理机的不予描述. Java内存模型 在Java中,虚拟机将运行时区域分成6中,如下图: 程序计数器:用来记录当前线程执行到哪一步操作.在多 ...
- C#中winform中panel重叠无法显示问题
C#中winform中panel重叠无法显示问题: 最近开发一个项目有个需求是需要多个模式来回切换的,本来考虑使用多个窗口来实现这个功能,但是这样做浪费资源,而且工作量大,所以想到使用panel控件来 ...