#資料結構基礎知識----陣列、LeetCode1
一、陣列
陣列是一系列具有連續記憶體空間的相同型別的元素。
①記憶體就是我們所說的RAM,也稱主存,是與處理器接近的用於儲存資訊的實物(如記憶體條)。陣列在記憶體中開闢已知長度的有限空間,這在很大程度上就限制了陣列的特性和適用範圍。
②且陣列往往在定義時就定義了資料型別,可以是string int這種內建的原始資料型別,也可以是自定義的資料型別(結構體),但前提是陣列內必須只有一個型別。
對於陣列的基本操作,
由於陣列是連續的記憶體空間,在增刪改時平均需要對一半的元素進行操作,這樣時間複雜度就達到了O(n)。
以陣列為基礎自定義一個順序表的類,
我們往往用兩個類來實現這樣一個順序表,在父類中列寫所有的基本操作,但前面加“virtual”即定義為虛擬函式,不需要實現。接著在派生類中繼承父類,自定義基本操作的實現。這樣的好處是使得父類能適應於更多的派生類,如用連結串列實現的時候父類就不需要修改只重新定義新的子類實現即可。
//父類 template<typename E> class List{ private: void operator = (const List&){} List(const List&){} public: List(){} virtual ~List(){} virtual int length() const = 0; virtual void moveToPos(int pos) = 0; virtual const E& getValue() const = 0; virtual int getValueLetter() const = 0; virtual int getValueNum() const = 0; virtual int getValueElse() const = 0; virtual void append(const E& item) = 0; virtual void moveToEnd() = 0; virtual void deleteNum() = 0; virtual void clear() = 0; virtual void insert(const E& item) = 0; virtual void moveToStart() = 0; virtual void prev() = 0; virtual void next() = 0; virtual int currPos() const = 0; virtual E remove() = 0; }; //子類 template<typename E> class AList:public List<E>{ private: int maxSize; int listSize; int curr; E* listArray; int numOfLetter; int numOfNum; int numOfElse; public: AList(int size = 1000){ maxSize = size; listSize = curr = 0; listArray = new E[maxSize]; numOfLetter = numOfNum = numOfElse = 0; } ~AList(){delete []listArray;} int length() const{return listSize;} void moveToPos(int pos){ if(pos >= 0 && pos <= listSize) curr = pos; } const E& getValue() const{ if(curr >= 0 && curr < listSize) return listArray[curr]; return listArray[0]; } int getValueLetter() const{ return numOfLetter; } int getValueNum() const{ return numOfNum; } int getValueElse() const{ return numOfElse; } void append(const E& item){ if(listSize < maxSize) listArray[listSize++] = item; } void moveToEnd(){curr = listSize-1;} void deleteNum(){ moveToEnd(); E x = getValue(); if((x >= 'a' && x <= 'z')||(x >= 'A' && x <= 'Z')){ numOfLetter++; } else if(x >= '0' && x <= '9'){ numOfNum++; listSize--; } else{ numOfElse++; } } void clear(){ delete []listArray; listSize = curr = 0; listArray = new E[maxSize]; } void insert(const E& item){ if(listSize < maxSize){ for(int i = listSize; i>curr; i--) listArray[i] = listArray[i-1]; listArray[curr] = item; listSize++; } } void moveToStart(){curr = 0;} void prev(){if(curr)curr--;} void next(){if(curr < listSize)curr++;} int currPos() const{return curr;} E remove(){ if(curr >= 0 && curr < listSize){ E it = listArray[curr]; for(int i = curr; i < listSize-1; i++) listArray[i] = listArray[i+1]; listSize--; return it; } return listArray[0]; } };
該順序表可計算字母數字的數目。
關於陣列的LeetCode一般都比較簡單,但是既然是總結就從簡單的開始。
二、LeetCode1
我用了比較容易想到的辦法,相當於暴力查找了:
class Solution { public int[] twoSum(int[] nums, int target) { int[] result = {0,0}; int target2; int temp; for(int i = 0; i < nums.length; i++){ target2 = nums[i]; temp = getIndex(nums, i, target-target2); if(temp > 0){ result[0] = i; result[1] = temp; } } return result; } public static int getIndex(int[] arr, int i, int value){ for(int x = i+1; x < arr.length; x++){ if(arr[x] == value){ return x; } } return -1; } }
過程中由於太久沒用java有點陌生,一直在找java自帶的搜尋方法,沒有找到,於是最後還是自己定義了一個方法找元素下標,其實吧自定義只是比分開寫簡潔一點沒啥用,執行能成功但是效果不佳,因為很明顯相當於兩層陣列的遍歷查詢,時間複雜度到了O(n^2)。
於是在提交記錄裡看到自己一年前用C++做的時候優化用了雜湊表,這裡應該也能用雜湊表優化一下。
嗐,java的雜湊表和C++稍微有點不一樣,我感覺java在呼叫上對新手不太友好,不百度我怎麼知道叫什麼函式啊!!而且C++可以直接.[]呼叫的地方在java這好多都得用函式www
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] result = {0,0};
int target2;
Map<Integer, Integer> hash = new HashMap<Integer, Integer>();
for(int i = 0; i < nums.length; i++){
target2 = target - nums[i];
if(hash.containsKey(target2)){
result = new int[]{hash.get(target2), i};
break;
}
hash.put(nums[i], i);
}
return result;
}
}
不過憑藉雜湊表優秀的時間複雜度O(1),這樣效率高了不少,針不戳啊~