1. 程式人生 > >Lettcode | Two Sum(兩個數的和等於定值)

Lettcode | 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

思路:

題目的要求是給定一個數組,找出陣列中和為一定值的兩個數。也就是給定一定值target,從陣列中要找出a+b=target。等式轉換一下,我們可以知道,a=target-b。所以我們要做的事情可以翻譯為,找到一個數a,滿足a與target-a都在陣列之中。 第一個思路,遍歷陣列中的某一個數,對於每個數再一次遍歷陣列中的所有數,找到滿足條件的兩個數。這個演算法的時間複雜度為O(n2),空間複雜度為O(1)。 第二個思路,在前一個演算法的基礎上降低時間複雜度。我們可以將陣列排序,然後定義兩個指標,一個指標從左向右,另一個從右向左,遍歷直到找到滿足條件的兩個數。由於排序的最佳時間複雜度為O(nlogn),兩個指標的遍歷時間複雜度為O(n)。所以總的時間複雜度為O(nlogn) 第三個思路,我希望通過O(n)的時間複雜度完成要求。第一遍O(n)的演算法將每個資料a對應的target-a建立查詢的資料結構,例如Hash表;第二遍遍歷時,查詢每個數是否在Hash表中,每次查詢時間複雜度為O(1),總的時間複雜度是O(n)。但是Hash表將需要一定的儲存空間,為了節省空間,我們可以採用bitmap的方法來最大化的壓縮空間複雜度。

說明:

1:這道題可以參考《【程式設計師程式設計藝術】第五章:尋找滿足和為定值的兩個或多個數》但該題目中建立hash表時用bitmap來實現,是連結中所沒有的。

原始碼:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//快速排序
int Position(int arr[],int lo,int hi)
{
    int key = arr[hi];
    int i = lo - 1;
    int temp;

    for(int j = lo;j < hi;j++){
        if(arr[j] < key){
            ++i;
            temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    ++i;
    temp = arr[i];
    arr[i] = arr[hi];
    arr[hi] = temp;

    return i;
}

void QuickSort(int arr[],int lo,int hi)
{
    int mid;
    if(lo < hi){
        mid = Position(arr,lo,hi);
        QuickSort(arr,lo,mid - 1);
        QuickSort(arr,mid + 1,hi);
    }
}

//bitmap實現
unsigned char *g_bitmap = NULL;
int g_size = 0;
int g_base = 0;

int bitmap_init(int size,int start)
{
    g_bitmap = (unsigned char *)malloc((size/8 + 1) * sizeof(char));
    if(g_bitmap == NULL)
        exit(1);
    g_base = start;
    g_size = size/8 + 1;

    memset(g_bitmap,0,g_size);
    return 1;
}

int bitmap_set(int index)
{
    int quo = (index - g_base)/8;
    int remainder = (index - g_base)%8;
    unsigned char x = 1 << remainder;   //x必須設為char字元,接下來要與一個位元組的資料相與

    if(quo >= g_size)
        return 0;
    g_bitmap[quo] |= x;

    return 1;
}

int bitmap_get(int i)
{
    int quo = i/8;
    int remainder = i%8;
    unsigned char x = 1 << remainder;
    unsigned char res;
    if(quo >= g_size)
        return 0;
    res = g_bitmap[quo] & x;

    return res > 0 ? 1 : 0;
}

int bitmap_data(int i)
{
    return i+g_base;
}

void bitmap_free(void)
{
    free(g_bitmap);
}

//找到合適的解
int FindTwoSum(int arr[],int key,int n,int *x,int *y)
{
    int i,j;

    for(i = 0,j = n-1;i < j;){
        if(arr[i]+arr[j] == key){
            *x = i;
            *y = j;
            return 1;
        }else if(arr[i] + arr[j] > key)
            --j;
        else
            ++i;
    }

    return 0;
}

void PrintArr(int arr[],int n)
{
    for(int i = 0;i < n;++i)
        printf("%d ",arr[i]);
    printf("\n");
}


int main(void)
{
    int n,index1,index2;
    int arr[] = {7,2,15,11};
    n = sizeof(arr)/sizeof(int);
#if 0
    PrintArr(arr,n);
    QuickSort(arr,0,n-1);
    PrintArr(arr,n);
    FindTwoSum(arr,9,n,&index1,&index2);
    printf("index1 = %d,index2 = %d",index1,index2);
#endif // 0

    bitmap_init(15,0);
    for(int i = 0;i < n;i++){
        bitmap_set(arr[i]);
    }
    int j = 0;
    for(int i = 0;i <= 15 && j < n;i++){
        if(bitmap_get(i))
            arr[j++] = bitmap_data(i);
    }
    PrintArr(arr,n);
    FindTwoSum(arr,9,n,&index1,&index2);
    printf("index1 = %d,index2 = %d",index1,index2);
    return 0;
}