刷題筆記8.5-8.9
刷題順序依照labuladong演算法小抄
兩數之和(8.5)
- 初始化陣列:
int[] num = new int<length>;
int[] num = {1,2,3,4};
其中陣列名代表指標變數,故不可以直接將陣列名a賦值給陣列名b
錯誤的複製:int[] b = a;
- 陣列元素複製:
假設陣列nums的元素複製到numsSort中:
int[] numsSort = (int[])Arrays.copyOf(nums,nums.length)
意為為numsSort指向的儲存區內開闢nums.length長度的空間,並複製nums - 呼叫Arrays靜態類中的方法可以直接運算元組
1) 陣列預設升序排列:Arrays.sort(nums) - 使用arraylist.indexOf(Object o)來定位指定元素索引
第一步:一個陣列或者其他集合類建立一個不可變的 List 集合時,我們可以使用 Arrays.asList() 來方便地轉換
String[] array = {"a","b","c","d"}; // 現有靜態陣列或集合
List<String> list = Array.asList(array); // 轉換為長度不可變的Arraylist
或者直接賦值
List<String> list = Arrays.asList("a", "b", "c")
第二步:int index = list.indexOf("b");
【注意】
Arrays.asList() 不支援基本資料型別的陣列,只能接受 Object 型別的引數或者陣列。基本資料型別(如 int, double, char 等)不是 Object 的子類,所以不能直接作為 Arrays.asList() 的引數。
如果傳入一個基本資料型別的陣列,Arrays.asList() 會把它當作一個 Object 型別的元素,而不是把它的每個元素當作 Object 型別。這樣就會導致返回的 List 只有一個元素,就是原始陣列本身。
- 如果想要把一個基本資料型別的陣列轉換成 List
使用迴圈遍歷陣列,並把每個元素新增到 List 中。這樣可以利用自動裝箱(autoboxing)的特性,把基本資料型別轉換成對應的包裝類(如 Integer, Double, Character 等)。
List<Integer> list = new ArrayList<>();
int[] array = {1,2,3};
for(int num:array){
list.add(num);
}
刷題總結(8.6)
- 靜態陣列在建立的時候就要確定陣列的元素型別和元素數量,連續記憶體必須一次性分配,分配完了之後就不能隨意增減了
int[] nums = new int[4];
Java Golang 這種語言,靜態陣列建立出來後會自動幫你把元素值都初始化為 0,所以不需要再顯式進行初始化。
2. 動態陣列底層還是靜態陣列,只是自動幫我們進行陣列空間的擴縮容,並把增刪查改操作進行了封裝,讓我們使用起來更方便而已
// 建立動態陣列
// 不用顯式指定陣列大小,它會根據實際儲存的元素數量自動擴縮容
ArrayList<Integer> arr = new ArrayList<>();
for (int i = 0; i < 10; i++) {
// 在末尾追加元素,時間複雜度 O(1)
arr.add(i);
}
// 在中間插入元素,時間複雜度 O(N)
// 在索引 2 的位置插入元素 666
arr.add(2, 666);
// 在頭部插入元素,時間複雜度 O(N)
arr.add(0, -1);
// 刪除末尾元素,時間複雜度 O(1)
arr.remove(arr.size() - 1);
// 刪除中間元素,時間複雜度 O(N)
// 刪除索引 2 的元素
arr.remove(2);
// 根據索引查詢元素,時間複雜度 O(1)
int a = arr.get(0);
// 根據索引修改元素,時間複雜度 O(1)
arr.set(0, 100);
// 根據元素值查詢索引,時間複雜度 O(N)
int index = arr.indexOf(666);
- 廣義的(雙指標)連結串列
資料結構體定義
private static class Node<E> {
E val; // 結點儲存的數值
Node<E> next; // 當前結點指向的下一個
Node<E> prev; // 當前結點指向的上一個
Node(Node<E> prev, E element, Node<E> next) {
this.val = element;
this.next = next;
this.prev = prev;
}
}
一條連結串列並不需要一整塊連續的記憶體空間儲存元素。連結串列的元素可以分散在記憶體空間的天涯海角,透過每個節點上的 next, prev 指標,將零散的記憶體塊串聯起來形成一個鏈式結構。
刷題總結(8.8)
- 關於優先順序佇列:
使用場景:對k個元素排序,將陣列/序列抽象為二叉堆
使用方法:
- 優先順序佇列初始化:
// 堆排序偽碼,對 arr 原地排序
// 時間複雜度 O(NlogN),空間複雜度 O(N)
int[] heapSort(int[] arr) {
int[] res = new int[arr.length];
PriorityQueue<int> pq = new MyPriorityQueue<>();
for (int x : arr)
pq.push(x);
// 元素出堆的順序是有序的
for (int i = 0; i < arr.length; i++)
res[i] = pq.pop();
return res;
}
- 優先順序佇列按特定規則比較排序
PriorityQueue<ListNode> pq = new PriorityQueue<>(
lists.length, (a, b)->(a.val - b.val));
(a, b)->(a.val - b.val)
是一個lambda表示式,它定義了優先佇列中元素的排序規則。在Java中,優先佇列預設是一個最小堆,這意味著它將根據提供的比較器來維護元素的順序,使得佇列頭部始終是“最小”的元素。
a.val - b.val
是一個比較操作,它比較兩個ListNode物件的val值。根據這個比較結果,優先佇列確定元素的順序,即 如果a.val - b.val的結果小於0,那麼a將被視為比b小,a會排在b前面。
綜上,上面這段程式碼表示:優先佇列儲存著ListNode型別的元素,但佇列是按照ListNode物件的val欄位進行排序,確保具有最小val值的ListNode物件始終位於佇列的頭部。
- 注意:優先順序佇列中的元素不可為空,否則會報
java.lang.NullPointerException
,在執行pq.add(x)時跟隨判斷