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 ...
随机推荐
- Find the Multiple POJ-1426
题目链接:Find the Multiple 题目大意 找出一个只由0和1组成的能整除n的数. 思路 所有由0和1组成的数可以看作是某个只由0.1组成的数a经过以下两种变化得到 1.a * 10 2. ...
- 快速入门和使用HTML–使用Django建立你的第一个网站
一 前记 你每天浏览的网页,通过网络看的新闻,看着淘宝京东的绚丽多彩的界面.是否想过这个问题,它是怎么实现的呢?有没有搜过相关的知识呢?假如没有,假如你是一位对事物好奇的主或者是做计算机相关东西的人. ...
- css3练习
读条的实现1 .div{position: relative;border: 1px solid #111;width: 80px;height: 60px} .div div{width: 20px ...
- java面向对象,数据类型深入
java程序员面试题day02 1.类和对象有什么区别? java中的类通过class关键字进行定义,代表的是一种抽象的集合,在类中可以定义各种的属性和方法,代表的是每一个类的实例的特定的数据和动作, ...
- kotlin -- 可见性修饰符
puiblic Kotlin的可见修饰符与Java类似,但是默认可见性不同,Java默认包私有,kotlin默认public ### internal internal 只在模块内部可见.一个模块就是 ...
- eclipse中Tomcat version 9.0 only supports J2EE 1.2, 1.3, 1.4, and Java EE 5, 6, 7, and 8 Web modules
eclipse中导入了一个别人的项目,运行时提示没有可以使用的服务器,如下: 查看了下项目属性设置中的服务器,还是提示没有可用服务器: 尝试对部署在已有服务器下的项目Add and Remove... ...
- CSS 选择符有哪些?哪些属性可以继承?优先级算法如何计算?
CSS 选择符有哪些? 1.id选择器(#id) 2.类选择器(.class) 3.标签选择器(div,h1,p) 4.相邻选择器(h1 + p) 5.子选择器(ul > li) 6.后代选择器 ...
- 02-35 scikit-learn库之支持向量机
目录 scikit-learn库之支持向量机 一.SVC 1.1 使用场景 1.2 代码 1.3 参数详解 1.4 属性 1.5 方法 二.LinearSVC 三.NuSVC 四.LinearSVR ...
- .Net Core API使用ODP.NET操作Oracle数据库
.Net Core API使用ODP.NET操作Oracle数据库 1.下载Oracle.ManagerDataAccess.Core. 右键依赖项——管理NuGet程序包. 在浏览选项中查询Orac ...
- netty源码解解析(4.0)-25 ByteBuf内存池:PoolArena-PoolChunk
PoolArena实现了用于高效分配和释放内存,并尽可能减少内存碎片的内存池,这个内存管理实现使用PageRun/PoolSubpage算法.分析代码之前,先熟悉一些重要的概念: page: 页,一个 ...