1. 程式人生 > >【leetcode】兩數相加(演算法)

【leetcode】兩數相加(演算法)

兩數之和

 

給定一個整數陣列和一個目標值,找出陣列中和為目標值的兩個數。

你可以假設每個輸入只對應一種答案,且同樣的元素不能被重複利用。

看到題目我首先想到的是將目標值(target)拆分,將目標值變成0+target,1+(target-1),...,(target/2)+(target-target/2).

由於第一次做演算法題,我這種思想在我剛準備打程式碼時就直接被我拋之腦後,因為這種思路其實很'暴力',陣列可能根本沒有這麼多數,如果給定的target很大,那我勢必會在拆分上花費很大的開銷。

那麼現在,我們可以改進,得到的是,直接用target減去數組裡的數,用得到的數去從數組裡找,這樣的話我們就節省很多。這是又有一個小問題,如果你從數組裡找,你每減一個數,你勢必需要遍歷一遍陣列。而我是將target減過的數放進List裡面,從後面找前面已有的數。

 

程式碼如下:

class Solution {
    public int[] twoSum(int[] nums, int target) {
         List list =new ArrayList<Integer>();
         int result[] = new int[2];
        for (int i = 0 ;i<nums.length;i ++){
            if (list.contains(target-nums[i]))
            {
                result[0]=list.indexOf(target-nums[i]);
                result[1]=i;
                break;
            }else {
                list.add(nums[i]);
            }
        }
        return result;
    }

}

時間複雜度為O(n),執行的時間大概為幾十ms,下面則是幾ms的程式碼;

 

class Solution {
    public int[] twoSum(int[] nums, int target) {
		// 先複製一份陣列
		int[] newNums = Arrays.copyOf(nums, nums.length);
		// 排序複製的陣列
        Arrays.sort(newNums);
        // 結果集
        int[] res = new int[2]; 
        // 迴圈遍歷每一個
        for (int i=0; i<newNums.length - 1; i++) {
        	// 如果剩餘的數只有一個,那麼判斷這一個,並退出迴圈
        	if (newNums.length-i-1 == 1) {
            	if (newNums[i]+newNums[i+1] == target) {
            		res = new int[]{i,i+1};
            	} else {
            		res = null;
            	}
            	break;
            }
        	
        	// 如果剩餘的不只一個,則用二分法
        	int num = newNums[i];
        	int rest = target-num;
        	
        	int start = i+1;
        	int end = newNums.length-1;
        	int mid; // = (start+end) / 2;
        	int src = -1;
        	while(start < end) {
        		mid = (start+end+1) / 2;
        		if (rest < newNums[mid]) {
        			end = mid-1;
        		} else if (rest > newNums[mid]) {
        			start = mid+1;
        		} else {
        			src = mid;
        			break;
        		}
        	}
        	if (start == end && newNums[start] == rest) {
        		src = start;
        	}
        	// 如果二分法找到,則退出迴圈
        	if (src != -1) {
        		res[0] = i;
        		res[1] = src;
        		break;
        	}
        }
        
        boolean flag1=false;
        boolean flag2=false;
        
        // 在原陣列中查詢位置
        for(int i=0; i<nums.length; i++) {
        	if (flag1 && flag2) break;
        	if (!flag1 && nums[i] == newNums[res[0]]) {
        		res[0] = i;
        		flag1 = true;
        		continue;
        	}
        	if (!flag2 && nums[i] == newNums[res[1]]) {
        		res[1] = i;
        		flag2 = true;
        	}
        }
		return res;
    }
}