Algorithm之3sum closest及負數在Java中的表示

[b][size=medium][color=green]由一道算法題想到的[/color][/size][/b]

[b]1、16. 3Sum Closest[/b]


Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution.

For example, given array S = {-1 2 1 -4}, and target = 1.

The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).


代碼:



import java.util.Arrays;

public class Solution {
public int threeSumClosest(int[] num, int target) {
int min = num[0] + num[1] + num[num.length -1];
Arrays.sort(num);
for(int i = 0; i < num.length -2; i++){
int lo = i + 1, hi = num.length - 1;
while(lo < hi){
int sum = num[i] + num[lo] + num[hi];
if(Math.abs(sum - target) < Math.abs(min - target))
min = sum;
if(sum >= target) hi--;
else lo++;
}
}
return min;
}
}




時間複雜度爲 O(n^2)
爲了加快運算效率,我想保存前一個的狀態值,記爲: preDelta
如果當前 delta 與 preDelta 的符號相同,且 delta 比 preDelta 的絕對值大,
則 break;

但是,在使用異或運算符( preDelta^delta )時,總是得不到想要的結果。
於是回查了一下負數在Java中是如何表示的。又回顧了一下基礎知識。

——————————————————————————————————————

[quote]
[b]什麼是2的補碼?[/b]

它是一種數值的轉換方法,要分二步完成:
第一步,每一個二進制位都取相反值,0變成1,1變成0。比如,00001000的相反值就是11110111。
第二步,將上一步得到的值加1。11110111就變成11111000。
所以,00001000的2的補碼就是11111000。也就是說,-8在計算機(8位機)中就是用11111000表示。
不知道你怎麼看,反正我覺得很奇怪,爲什麼要採用這麼麻煩的方式表示負數,更直覺的方式難道不好嗎?


[b]2的補碼的好處[/b]

首先,要明確一點。計算機內部用什麼方式表示負數,其實是無所謂的。只要能夠保持一一對應的關係,就可以用任意方式表示負數。所以,既然可以任意選擇,那麼理應選擇一種最方便的方式。
2的補碼就是最方便的方式。它的便利體現在,所有的加法運算可以使用同一種電路完成。
還是以-8作爲例子。
假定有兩種表示方法。一種是直覺表示法,即10001000;另一種是2的補碼錶示法,即11111000。請問哪一種表示法在加法運算中更方便?
隨便寫一個計算式,16 + (-8) = ?
16的二進制表示是 00010000,所以用直覺表示法,加法就要寫成:
 00010000
+10001000
---------
 10011000
可以看到,如果按照正常的加法規則,就會得到10011000的結果,轉成十進制就是-24。顯然,這是錯誤的答案。也就是說,在這種情況下,正常的加法規則不適用於正數與負數的加法,因此必須制定兩套運算規則,一套用於正數加正數,還有一套用於正數加負數。從電路上說,就是必須爲加法運算做兩種電路。
現在,再來看2的補碼錶示法。
 00010000
+11111000
---------
100001000
可以看到,按照正常的加法規則,得到的結果是100001000。注意,這是一個9位的二進制數。我們已經假定這是一臺8位機,因此最高的第9位是一個溢出位,會被自動捨去。所以,結果就變成了00001000,轉成十進制正好是8,也就是16 + (-8) 的正確答案。這說明了,2的補碼錶示法可以將加法運算規則,擴展到整個整數集,從而用一套電路就可以實現全部整數的加法。

[/quote]
——————————————————————————————————————


所有的數在Java中[b]都是[/b]以其二進制的[b]補碼[/b]形式存放的。

正數的補碼是其自身
負數的補碼是:

負數的絕對值按位取反後 + 1


可以看到:(-0)


/*

在做減法的情況下:


00000000
=
11111111

+ 00000001

---------------------------------------

100000000

舍掉最高位的溢出,結果還是 0


因爲是做減法(加一個負數),如果不夠減需要借 1 位。
所以把負數拆分成: 絕對值取反 + 1 這種形式來表示。
把這種表示方式稱爲:負數的二進制表示法的補碼。簡稱:二進制補碼

得到的結果就是代表正數的負值——負數。
然後就可以對負值進行加法運算了。
奇怪的是,這樣做加法運算,居然就是正確的。


下面的步驟可以實現:正數 + 負的正數 = 0

1、正數 + 正數各位取反 = 最大值(所有位爲 1)

2、(所有位爲 1) + 1 = 0 (捨去溢出位)

--------------------------------------------------

綜合起來:

正數 + 正數各位取反 + 1 = 0

正數 + (正數各位取反 + 1) = 0

正數 + (補碼) = 0

正數 + (負數) = 0


--------------------------------------------------

上面只是 正數 + 負數 ,(兩數絕對值相等)
還有 大正數 + 負小正數,
還有 負數 + 負數 的情況,不在此證明。

*/



這種表示法可以使計算器只用加法一種電路就可以完成加減乘除四種運算。
(除法是減法,乘法是加法)


引用:

https://leetcode.com/problems/3sum-closest/

http://www.ruanyifeng.com/blog/2009/08/twos_complement.html


-
發佈了279 篇原創文章 · 獲贊 4 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章