给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
示例 1:
输入: [2,2,1]
输出: 1
对异或的考察
异或:相同为0,不同为1 。异或同一个数两次,原数不变。 a^b^b = a;
-
交换律:a ^ b ^ c <=> a ^ c ^ b
-
任何数于0异或为任何数 0 ^ n => n
-
相同的数异或为0: n ^ n => 0
public int singleNumber(int[] nums){
int a = 0;
for(int i=0;i<nums.length;i++){
a ^= nums[i];
}
return a;
}
个整型数组里除了两个数字之外,其他的数字都出现了两次,请写程序找出这两个只出现一次的数字。
例如输入数组{2, 4, 3, 6, 3, 2, 5 },因为只有4 、6 这两个数字只出现一次,其他数字都出现了两次,所以输出4和6 。
public static int[] findNumOnce(int[] data) {
int[] result = {0, 0};
if (data == null || data.length < 2) {
return result;
}
int xor = 0;
for (int i : data) {
// 这样得到两个只出现一次的数的异或
// 根据题意这个值不是0,那么必然有一位为1,
xor ^= i;
}
// 我们从右边找出第一个为1 的位的索引
int indexOf1 = findFirstBit1(xor);
// 根据那一位将数组分成那一位为1 的与那一位为0 的两组
for (int i : data) {
if (isBit1(i, indexOf1)) {
// 使用异或操作将分开的两个相同的除去。
result[0] ^= i;
} else {
result[1] ^= i;
}
}
return result;
}
private static int findFirstBit1(int num) {
int index = 0;
while ((num & 1) == 0 && index < 32) {
num >>>= 1;
index++;
}
return index;
}
private static boolean isBit1(int num, int indexBit) {
num >>>= indexBit;
return (num & 1) == 1;
}
不用加减乘除做加法
public static int add(int x, int y) {
int sum;
int carry;
do {
sum = x ^ y;
// x&y的某一位是1说明,它是它的前一位的进位,所以向左移动一位
carry = (x & y) << 1; // 1 & 1 = 1 <<
x = sum;
y = carry; // y != 0; 说明有进位,需要加一下
} while (y != 0);
return x;
}
罗马数字包含以下七种字符: I
, V
, X
, L
,C
,D
和 M
。
字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 罗马数字 2 写做 II
,即为两个并列的 1。12 写做 XII
,即为 X
+ II
。 27 写做 XXVII
, 即为 XX
+ V
+ II
。
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII
,而是 IV
。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX
。这个特殊的规则只适用于以下六种情况:
I
可以放在V
(5) 和X
(10) 的左边,来表示 4 和 9。X
可以放在L
(50) 和C
(100) 的左边,来表示 40 和 90。C
可以放在D
(500) 和M
(1000) 的左边,来表示 400 和 900。
给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。
示例 1:
输入: "III"
输出: 3
示例 2:
输入: "IV"
输出: 4
示例 3:
输入: "IX"
输出: 9
示例 4:
输入: "LVIII"
输出: 58
解释: L = 50, V= 5, III = 3.
示例 5:
输入: "MCMXCIV"
输出: 1994
解释: M = 1000, CM = 900, XC = 90, IV = 4.
遍历一般吧转换后的值加一遍,不过要在途中加判断,如果前一个与当前的构成一个数就把对加的减去
public int romanToInt(String s) {
int result = 0;
int len = s.length();
int p = 0;
for (int i=0;i<s.length();i++){
result += prase(s.charAt(i));
if (i >0){
// 先加再减
if ((s.charAt(i) == 'V' || s.charAt(i) == 'X') && s.charAt(i-1) == 'I')
result -= 2;
else if ((s.charAt(i) == 'L' || s.charAt(i) == 'C') && s.charAt(i-1) == 'X')
result -= 20;
else if ((s.charAt(i) == 'D' || s.charAt(i) == 'M') && s.charAt(i-1) == 'C')
result -= 200;
}
}
return result;
}
private int prase(char a){
int val = 0;
switch (a){
case 'I':
val = 1;
break;
case 'V':
val = 5;
break;
case 'X':
val = 10;
break;
case 'L':
val = 50;
break;
case 'C':
val = 100;
break;
case 'D':
val = 500;
break;
case 'M':
val = 1000;
break;
}
return val;
}
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
循环遍历 ,新建了一个Node 节点,如果l1 小就指向l1,否则就指l2,这样知道出现null 的为止(其实每次只移动l1与l2 的一个),因为可能有链表长,而且之后还大的,所以还需要两个判断,如果有不是null 的就指向它,但最多只能有一个不是null
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode node= new ListNode(0);
ListNode cur = node;// 移动指针
while (l1 != null && l2 != null){
if (l1.val < l2.val){
cur.next = l1;
cur = cur.next;
l1 = l1.next;
}else {
cur.next = l2;
cur = cur.next;
l2 = l2.next;
}
}
if (l1 != null){
cur.next = l1;
}
if (l2 != null){
cur.next = l2;
}
return node.next;
}
给定一个整数,编写一个函数来判断它是否是 2 的幂次方。
// 如果一个数字是 2 的幂次方的话,那么它的二进制表示中肯定只有一位是1,如果n&(n-1) = 0,那么二进制表示只有一个1,即为2的幂
public boolean isPowerOfTwo(int n) {
if(n<1) return false;
return (n & n-1) == 0;
}