程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> LeetCode 第一題,Two Sum

LeetCode 第一題,Two Sum

編輯:C++入門知識

LeetCode 第一題,Two Sum


今天早上起來去機房的路上還在想,一直不做算法題老是覺得不踏實。做做題總是讓自己覺得自己真的在做做學習。。。。


這也算是一種強迫症吧。

那就從今天開始做做LeetCode,因為好久沒做過了,所以第一題還是看了別人的題解和思路,算是找找感覺。


總的來說第一題是個水。。。。



題目還原

Two Sum

Given an array of integers, find two numbers such that they add up to a specific target number.

The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are not zero-based.

You may assume that each input would have exactly one solution.

Input: numbers={2, 7, 11, 15}, target=9
Output: index1=1, index2=2

中文意思就是給你一個整數數組和一個目標值,找出這個數組中的兩個元素的和為該目標值的元素的下標,輸出為index1和index2,按從小到大的序輸出。且假定每個數組都恰好包含一個解,即使,恰好每個給定的數組都有且只有一種符合的結果。

解答

首先,做這種的題目一般都是需要排序的,為了速度,也為了方便查找。

當然,不排序也可以做,,不過那個復雜度貌似有點不合理。

雖然給定的數組不是按序給定的,但是,我們要知道,在這個算法的世界裡面,有序的話,一切都很簡單了。

有序的價值啊。可惜我的生活現在還是有些混亂無章。。。。

但是因為最後要返回的是原數組的元素下標,因此,我們必須要在使用原數組的空間做一個副本。。。。

然後就是打副本,首先假設副本是從小到大,至於怎麼打,我想到一種方法:

選取左右兩個游標,取二者之和,若和等於目標值,將這個所代表的元素在原數組查找確定下標,然後保存在index中。留待返回。

若和大於目標值,則讓右下標往左移;

若和小於目標值,則讓左下標往右移。

直至左右相等之前為止。

因此實現的代碼如下:

/*************************************************************************
> File Name: twosum.cpp
> Author: SuooL
> Mail: [email protected]
> Created Time: 2014年07月31日 星期四 20時14分32秒
************************************************************************/

class Solution
{
    public:
    vector twoSum(vector &numbers, int target)
    {
        // Note: The Solution object is instantiated only once and is reused by each test case.
        vector num = numbers;
        std::sort(num.begin(), num.end());

        int length = numbers.size();
        int left = 0;
        int right = length - 1;
        int sum = 0;

        vector index;

        while(left < right)
        {
            sum = num[left] + num[right];

            if(sum == target)
            {
                // find the index from the old array
                for(int i = 0; i < length; ++i)
                {
                    if(numbers[i] == num[left])
                    {
                        index.push_back(i + 1);
                    }
                    else if(numbers[i] == num[right])
                    {
                        index.push_back(i + 1);
                    }
                    if(index.size() == 2)
                    {
                        break;
                    }
                }
                break;
            }
            else if(sum > target)
            {
                --right;
            }
            else
            {
                ++left;
            }
        }

        return index;
    }
};


Python代碼:

#!/usr/bin/env python
# coding=utf-8
class Solution:
    # @return a tuple, (index1, index2)
    def twoSum(self, num, target):
     
        numbers = sorted(num)

        length = len(num)
        left = 0
        right = length - 1

        index = []

        while left < right: 
            sums = numbers[left] + numbers[right]

            if sums == target:
                for i in range(length):
                    if num[i] == numbers[left]:
                        index.append(i + 1)
                    elif num[i] == numbers[right]:
                        index.append(i + 1)
                    
                    if len(index) == 2:
                        break

                break
            elif sums > target:
                right -= 1
            else:
                left += 1

        result = tuple(index)

        return result
下面的一個類似的解法是網絡上的,用了最新的C++11標准。表示膜拜。

/*************************************************************************
> File Name: twosum_c11.cpp
> Author:SuooL 
> Mail: [email protected]
> Created Time: 2014年07月31日 星期四 20時18分45秒
************************************************************************/

class Solution 
{
    public:
    typedef pair valoffset_pair_t;


    vector twoSum(vector &numbers, int target) 
    {
        vector new_array;
        // Preallocate the memory for faster push_back
        new_array.reserve(numbers.size());

        // generate the new array
        int index=0;
        for(auto i : numbers)
        new_array.push_back(valoffset_pair_t(i, ++index));
        // Note: here the index is already increased, so 
        // the new indices are not zero based

        // sort it!
        sort(begin(new_array), end(new_array), 
             [&](const valoffset_pair_t& v1, const valoffset_pair_t& v2) -> bool
             {
                 return v1.first < v2.first;
             }
            );

        // now find the right pair using two pointers
        auto p_left=begin(new_array);
        auto p_right=end(new_array); 
        p_right--;  // make it locate at the last position
        int sum = p_left->first + p_right->first;

        // it is guaranteed to have one exact solution
        while(sum!=target)
        {
            sum = p_left->first + p_right->first;
            if (sum > target)
            p_right--;
            else if (sum < target)
            p_left++;
            else
            break;
        }
        return vector(
            {min(p_left->second, p_right->second),
             max(p_left->second, p_right->second)});
    }
};

同時,最後看到了,只用了O(n)的hashmap方法,思路是循環一次,每次都判斷當前數組索引位置的值在不在hashtable裡,不在的話,加入進去,key為數值,value為它的索引值;在的話,取得他的key,記為n(此時n一定小於循環變量i),接下來再在hashtable中查找(target-當前數值)這個數,利用了hashtable中查找元素時間為常數的優勢,如果找到了就結束,此處需要注意的是,如果數組中有重復的值出現,那麼第二次出現時就不會加入到hashtable裡了,比如3,4,3,6;target=6時,當循環到第二個3時,也可以得到正確結果。

代碼如下:

class Solution {
public:
    vector twoSum(vector &numbers, int target) 
	{
        int i, sum;
        vector results;
        map hmap;
        for(i=0; i(numbers[i], i));
            }
			// find the number which equal to target - numbers[i]
            if(hmap.count(target-numbers[i]))
			{
                int n=hmap[target-numbers[i]];
                if(n

Python:

class Solution:
	# @return a tuple, (index1, index2)
	def twoSum(self, num, target):
		length = len(num)
		index = []
		hash_tab = {}
		for i in range(length):
			if( not hash_tab.has_key(num[i])) :
				pair = {num[i] : i}
				hash_tab.update(pair)
			if( hash_tab.has_key(target - num[i] )) :
				n = hash_tab[target-num[i]]
				if n< i :
					index.append(n + 1)
					index.append(i + 1)
					result = tuple(index)
					return result
		return result

Summary

首先想到的就是兩層遍歷法,但是顯然時間復雜度太高,是O(N^2),不符合要求. 於是就應該想如何降低復雜度,首先應該想將逐個比較轉變為直接查找,即首先計算出 target與當前元素的差,然後在序列中尋找這個差值,這樣首先就把問題簡化了,而尋找的過程可以先對序列進行快排,然後二分查找,這樣整體的復雜度就降低為 O(N*logN) 了;查找最快的方法是利用一個 map容器存儲每個元素的索引,這樣取得某個特定元素的索引只需要常數時間即可完成,這樣就更快了,最多只需遍歷一次序列,將元素及其索引加入map中,在遍歷的過程中進行對應差值的查找,如果找到了就結束遍歷,這樣時間復雜度最多為 O(N),It's amazing!
總之,這是自己做的第一道leetcode題,感覺比其他oj要嚴格一些,比如這題有嚴格的執行時間要求,O(N^2)的不能過,可以給自己優化程序的理由。繼續加油!
提交記錄:

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved