刷演算法,這些api不可不知!

三分惡發表於2021-07-16

大家好,我是老三,最近在刷演算法,發現有些api記得不熟,所以整理了一波,如果你也在刷題,趕緊收藏吧!

集合

在刷題中,各種資料結構是我們常常用到的,例如棧實現迭代、雜湊儲存鍵值對等等,我們來看看常用集合和相關api。

類/介面 描述 方法
String 字串 charAt toCharArray split substring indexOf lastIndexOf replace length
List 列表 add remove get size subList
Stack push pop peek isEmpty size
Queue 佇列 offer poll peek isEmpty size
Deque 雙向佇列 offerFirst offerLast pollFirst pollLast peekFirst peekLast isEmpty size
PriorityQueue 優先佇列 offer poll peek isEmpty size
Set add remove contains isEmpty size first(TreeSet) last(TreeSet)
Map put get getOrDefault containsKey containsValue keySet values isEmpty size

陣列

陣列就不用多說什麼了,大家最熟悉的資料結構。

Arrays

Arrays是比較常用的陣列工具類,可以完成排序、拷貝等功能。

  • 從小到大排序:Arrays.sort(int[] arr) Arrays.sort(int[] arr, int fromIndex, int toIndex)
Arrays.sort(int[] arr, int fromIndex, int toIndex, 比較器);   //一定是需要泛型

Arrays.sort(arr, (o1, o2) -> o2 - o1);   //陣列全部 從大到小排序 跟Collections.sort()一樣

Arrays.sort(arr, 0, 3, (o1, o2) -> o2 - o1);   //從大到小排序,只排序[0, 3)
  • 拷貝:Array.copyOf
int[] a = new int[5];
int[] newA = Array.copyOf(a, 5);

列表

列表主要有兩種實現,分別是順序表連結串列

列表實現

順序表本質是一個可以動態擴容的陣列,在Java中的實現是ArrayList

連結串列是一個雙向連結串列,Java中連結串列的實現為LinkedListLinkedList在Java中可謂是非常強大的一個集合類,它還可以作為雙向佇列、棧來使用。

注意,ArrayList的擴容需要將舊的陣列的元素複製到新的陣列,時間複雜度為O(n)。

基本方法

  • 構造
List<Integer> array = new ArrayList<>();    // 順序表
// Set<Integer> a = new HashSet....
List<Integer> b = new ArrayList<>(a);     //接受一個集合容器
  • get
get(int index)    // 返回元素位置在index的元素e --- array O(1), list O(n)
  • size

size()    // 返回陣列/連結串列長度 --- O(1)
  • add
add(E e)    // 在尾部新增一個元素e --- O(1)
add(int index, E e)    // 在index位置插一個元素e --- O(n)
  • remove
.remove(int index)    // 刪除位於index的元素,並返回刪除元素e --- 刪除最後元素為O(1), 其餘為O(n)
//刪除最後元素 list.remove(list.size() - 1);
  • subList
.subList(int from, int to)    // 相當於返回原陣列的一個片段,但不要對其進行改動,改動會影響原陣列 --- O(1)
// List<Integer> list, 對原來的list和返回的list做的“非結構性修改”(non-structural changes),
//都會影響到彼此對方. 如果你在呼叫了sublist返回了子list之後,如果修改了原list的大小,那麼之前產生的子list將會失效,變得不可使用

集合工具

Collections是集合工具類,提供了一些操作集合的方法。

  • 排序
Collections.sort(list); 從小到大排序
Collections.sort(list, (o1, o2) -> o2 - o1); 從大到小排序, 第二個引數為一個比較器

兩種實現,ArrayList利於查詢,LinkedList利於增刪。

大概對比如下:

操作 ArrayList LinkedList
get(int index) O(1) O(n),平均 n / 4步
add(E element) 最壞情況(擴容)O(n) ,平均O(1) O(1)
add(int index, E element) O(n) ,平均n / 2步 O(n),平均 n / 4步
remove(int index) O(n) 平均n /2步 O(n),平均 n / 4步

Java中定義了Stack介面,實現類是VectorVector是一個祖傳集合類,不推薦使用。

那應該用什麼呢?

Deque介面實現了完善堆疊操作集合,它有一個我們熟悉的實現類LinkedList

棧

  • 構造
Deque<Integer> stack=new LinkedList<>();
  • push
push(E e);    // 入棧元素e, 返回值為元素e --- O(1)
  • pop
.pop();    // 出棧一個元素,返回出棧元素e --- O(1)
  • peek
peek();    // 檢視棧頂元素, 返回值為棧頂元素e --- O(1)
  • isEmpty
isEmpty()    // 若棧空返回true, 否則返回false --- O(1)
  • size
size()    // 返回棧中元素個數 --- O(1)

佇列

佇列s是一種先進先出的結構,在Java中的介面定義是Queue,具體實現還是我們的老朋友LinkedList

單向佇列

  • 構造
Queue<Integer> q = new LinkedList<>();
  • offer
offer(E e);    // 隊尾加入元素e。 若成功入隊返回值true,否則返回false --- O(1)
  • poll
poll();    // 出隊頭,返回出隊元素e --- O(1)
  • peek
peek();    // 檢視隊頭元素, 返回值隊首元素e --- O(1)
  • isEmpty
isEmpty()    // 若隊空返回true, 否則返回false --- O(1)
  • size
size()    // 返回隊中元素個數 --- O(1)

雙向佇列

Queue有一個子介面Dueue,即雙向佇列,和單向佇列不同,它的出隊入隊可以從兩個方向。

雙向佇列

  • 構造
Dueue<Integer> q = new LinkedList<>();
  • offFirst
offFirst(Object e)   // 將指定元素新增到雙端佇列的頭部 --- O(1)
  • offLast
offLast(Object e)   //將指定元素新增到雙端佇列的尾部 --- O(1)
  • pollFirst
pollFirst()   //獲取並刪除雙端佇列的第一個元素 --- O(1)
  • pollLast
pollLast()   //獲取並刪除雙端佇列的最後一個元素 --- O(1)
  • peekFirst
peekFirst()   //獲取但不刪除雙端佇列的第一個元素 --- O(1)
  • peekLast
peekLast()   //獲取但不刪除雙端佇列的最後一個元素 --- O(1)

優先佇列

優先佇列是一種比較特殊的佇列,儲存佇列元素的順序不是按照元素新增的順序來儲存的,而是在新增元素的時候對元素的大小排序後再儲存。

所以在隊頭的元素不是按照先後順序,而是按照大小順序。

在Java中的實現是PriorityQueue,底層是一棵樹, 以小根堆為例。對於任意結點來說,該節點的值比其左右孩子的值都要小。 (就是最上面的結點最小)。 大根堆類似,最上面結點最大

  • 構造
    • 小根堆
Queue<Integer> minH = new PriorityQueue<>();    // 小根堆,預設大小為11 相當於  new PriorityQueue<>(11)
Queue<Integer> minH = new PriorityQueue<>(100);  // 定義一個預設容量有100的小根堆。在當中增加元素會擴容,只是開始指定大小。不是size,是capacity
    • 大根堆
Queue<Integer> maxH = new PriorityQueue<>((i1, i2) -> i2 - i1);    // 大根堆,預設大小為11 相當於  new PriorityQueue<>(11, (i1, i2) -> i2 - i1)
Queue<Integer> maxH = new PriorityQueue<>(100, (i1, i2) -> i2 - i1);    // 定義一個預設容量有100的大根堆。在當中增加元素會擴容,只是開始指定大小
  • offer
offer(E e);    // 在堆中加入元素e,並調整堆。若成功入堆返回值true,否則返回false --- O(logN)
  • poll
poll();    // 彈出堆頂元素,並重新調整堆,返回出隊元素e --- O(logN)
  • peek
peek();    // 檢視堆頂元素, 返回值堆頂元素e --- O(1)

雜湊表

雜湊表示一種<key,value>型的資料結構,在Java中的實現是HashMap

  • 構造
Map<Characters, Integer> map = new HashMap<>();
  • put
put(K key, V value);    // 在Map中加入鍵值對<key, value>。返回value值。如果Map中有key,則replace舊的value --- O(1)
  • get
get(K key);    // 返回Map中key對應的value。若Map中沒有該key,則返回null --- O(1)
  • getOrDefault
getOrDefault(K key, V defaultValue);    // 返回Map中key對應的value。若Map中沒有該key,則返回defaultValue --- O(1)

// For example:
// Map<Character, Integer> map = new HashMap<>();
// if (...)    // 如果發現k,則k在Map中的值加1。沒一開始沒有k,則從0開始加1。(相當於給了key在Map中的一個初試值)
    map.put('k', map.getOrDefault('k', 0) + 1);
  • containsKey
containsKey(Key key);    // 在Map中若存在key,則返回true,否則返回false --- O(1)

get(x) == null // 可以代替改用法
  • keySet
keySet();    // 返回一個Set,這個Set中包含Map中所有的Key --- O(1)

// For example:
// We want to get all keys in Map
// Map<Character, Integer> map = new HashMap<>();
for (Character key : map.keySet()) {
    // Operate with each key
}
  • values
values();    // 返回一個Collection<v>,裡面全是對應的每一個value --- O(1)

// For example:
// We want to get all values in Map
// Map<Character, Integer> map = new HashMap<>();
for (Integer value : map.values()) {
    // Operate with each values
}
  • isEmpty
isEmpty()    // 若Map為空返回true, 否則返回false --- O(1)
  • size
.size()    // 返回Map中中鍵值對<K, V>的個數 --- O(1)

Set

Set是一種沒有重複元素的集合,常用的實現是HashSet

  • 構造
Set<Integer> set = new HashSet<>();
List<Integer> list = new ArrayList<>....;
Set<Integer> set = new HashSet<>(list);
  • add
.add(E e);    // 在集合中新增元素E e, 若成功新增則返回true,若集合中有元素e則返回false --- O(1)
  • remove
remove(E e);    // 在集合中刪除元素e,若刪除成功返回true;若集合中沒有元素e,返回false --- O(1)
  • contains
contains(E e);    // 若存在元素e,則返回true,否則返回false --- O(1)
  • isEmpty
isEmpty()    // 若集合為空返回true, 否則返回false --- O(1)
  • size
size()    // 返回集合中中元素個數 --- O(1)
  • first
first()    // 返回集合裡的最小值(若給了比較器從大到小則是返回最大值)
  • last
last()    // 返回集合裡的最大值(若給了比較器從大到小則是返回最小值)

字串

String

不可變數(相當於只讀final修飾),每個位置元素是個char。

字串

  • 初始化

字串複製初始化

String s = ``"abc"``;

基於另外一個字串

// s = "abc"``String s2 = ``new` `String(s);

基於char[]

// s = "abc";
// char[] c = s.toCharArray();
String s3 = new String(c);

// 可以偏移
// public String(char value[], int offset, int count)
String s4 = new String(c, 1, 2);    // [offset, offset + count) [)

// 把char[] 變成字串
char[] ch = {'a', 'b', 'c'};
String.valueOf(ch);
  • charAt
charAt(int index);    // 返回index位置的char --- O(1)
  • length
length();    // 返回字串長度 --- O(1)
  • substring
substring(int beginIndex, int endIndex);    // 返回字元片段[beginIndex, endIndex) --- O(n)

substring(int beginIndex);    // 返回字元片段[beginIndex, end_of_String) 就是從beginIndex開始後面的 ---- O(n)
  • indexOf
indexOf(String str)    // 返回str第一個出現的位置(int),沒找到則返回-1。 --- O(m * n) m為原串長度, n為str長度
// (假如要找一個字元char c,str可以表示成String.valueOf(c),然後作為引數傳進去.

s.indexOf(String str, int fromIndex);    // 同上,但從fromIndex開始找 --- O(m * n)
  • lastIndexOf
lastIndexOf(String str);    // 返回str最後出現的位置(int),沒找到則返回-1。 --- O(m * n) m為原串長度, n為str長度
// (假如要找一個字元char c,str可以表示成String.valueOf(c),然後作為引數傳進去.

lastIndexOf(String str, int fromIndex);    // 同上,
//但從fromIndex開始從後往前找 [0 <- fromIndex] --- O(m * n)
  • replace
replace(char oldChar, char newChar);    // 返回一個新字串String,其oldChar全部變成newChar --- O(n)
  • toCharArray
toCharArray();   // 返回char[] 陣列。 把String程式設計字元陣列 --- O(n)
  • trim
trim();    // 返回去除前後空格的新字串 --- O(n)
  • split
split(String regex);    // 返回 String[],以regex(正規表示式)分隔好的字元換陣列。 ---- O(n)

// For example
// 從非"/"算起 若"/a/c" -> 會變成"" "a" "c"
String[] date = str.split("/");     // date[0]:1995 date[1]:12 date[2]:18 --- O(n)
  • toLowerCase, toUpperCase
s = s.toLowerCase();    // 返回一個新的字串全部轉成小寫 --- O(n)
s = s.toUpperCase();    // 返回一個新的字串全部轉成大寫 --- O(n)

StringBuilder

由於String是所謂的不可變類,使用 str+這種形式拼接字串實際上,是JVM幫助迴圈建立StringBuilder來拼接,所以拼接字串最好用StringBuilder。

  • 構造
StringBuilder sb = new StringBuilder();
  • charAt
charAt(int index);    // 返回index位置的char --- O(1)
  • length
length();    // 返回緩衝字串長度 --- O(1)
  • apped
append(String str)   // 拼接字串 --- O(n)
  • toString
toString();    // 返回一個與構建起或緩衝器內容相同的字串 --- O(n)

數學

最大最小值

在一些題目裡,需要用到最大,最小值,Java中各個資料型別的最大最小值定義如下:

fmax = Float.MAX_VALUE;

fmin = Float.MIN_VALUE;

dmax = Double.MAX_VALUE;

dmin = Double.MIN_VALUE;

bmax = Byte.MAX_VALUE;

bmin = Byte.MIN_VALUE;

cmax = Character.MAX_VALUE;

cmin = Character.MIN_VALUE;

shmax = Short.MAX_VALUE;

shmin = Short.MIN_VALUE;

imax = Integer.MAX_VALUE;

imin = Integer.MIN_VALUE;

lmax = Long.MAX_VALUE;

lmin = Long.MIN_VALUE;

Math

  • max
Math.max(long a, long b);    //返回兩個引數中較大的值
  • sqrt
Math.sqrt(double a);    //求引數的算術平方根
  • abs
Math.abs(double a);  //返回一個型別和引數型別一致的絕對值
  • pow
Math.pow(double a, double b);  //返回第一個引數的第二個引數次方。
  • ceil
Math.ceil(double x);   //向上取整
  • floor
Math.floor(double x);  //向下取整
  • round
Math.round(double x);   //四捨五入

"簡單的事情重複做,重複的事情認真做,認真的事情有創造性地做!"——

我是三分惡,一個能文能武的全棧開發。

點贊關注不迷路,我們們下期見!


參考:

[1].Java刷題常用API

[2].Java 刷題集合類

相關文章