基礎部分
912. 排序數組
中等
給你一個整數數組 nums
,請你將該數組升序排列。
示例 1:
輸入:nums = [5,2,3,1]
輸出:[1,2,3,5]
示例 2:
輸入:nums = [5,1,1,2,0,0]
輸出:[0,0,1,1,2,5]
提示:
1 <= nums.length <= 50000
-50000 <= nums[i] <= 50000
class Solution {
public int[] sortArray(int[] nums) {
quickSort(nums,0,nums.length-1);
return nums;
}
private void quickSort(int[] nums, int l, int r) {
if (l >= r) return;
int mid = pattern(nums,l,r);
if (mid != l){
int tmp = nums[mid];
nums[mid] = nums[l];
nums[l] = tmp;
}
quickSort(nums,l,mid-1);
quickSort(nums,mid+1,r);
}
private int pattern(int[] nums, int l, int r) {
int first = nums[l];
int i = l;
int j = r + 1;
while (i < j){
do { //先判斷后加,會多加一個,所以 do..while
i++;
}while (nums[i] < first && i < r);
do {
j--;
}while (nums[j] > first && j > l);
if (i >= j) break; //弄多了就換回來了,所以檢查一下
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
return j;
}
}
215. 數組中的第K個最大元素
中等
在未排序的數組中找到第 k 個最大的元素。請注意,你需要找的是數組排序后的第 k 個最大的元素,而不是第 k 個不同的元素。
示例 1:
輸入: [3,2,1,5,6,4] 和 k = 2
輸出: 5
示例 2:
輸入: [3,2,3,1,2,4,5,5,6] 和 k = 4
輸出: 4
說明:
你可以假設 k 總是有效的,且 1 ≤ k ≤ 數組的長度。
//減治的快排
class Solution {
public int findKthLargest(int[] nums, int k){
quickSort(nums,k-1,0,nums.length-1);
return nums[k-1];
}
private void quickSort(int[] nums, int index, int l, int r) {
if (l >= r) return;
int mid = pattern(nums,l,r);
if (mid != l){
int tmp = nums[mid];
nums[mid] = nums[l];
nums[l] = tmp;
}
if (mid > index) quickSort(nums,index,l,mid-1);
else quickSort(nums,index,mid+1,r);
}
private int pattern(int[] nums, int l, int r) {
int first = nums[l];
int i = l;
int j = r + 1;
while (i < j){
do {
i++;
}while (nums[i] > first && i < r);
do {
j--;
}while (nums[j] < first && j > l);
if (i >= j) break;
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
return j;
}
}
//堆排序:建立k大小的小根堆,堆頂即為所求
class Solution {
public int findKthLargest(int[] nums, int k){ //O(n*logk)
//PriorityQueue 優先級隊列,底層是二叉堆
//(n1,n2)->n1-n2 小根堆
PriorityQueue<Integer> heap = new PriorityQueue<>((n1,n2)->n1-n2);
for (int num : nums) {
heap.add(num); //O(logk)
if (heap.size() > k) heap.poll(); //O(logk)
}
return heap.poll();
}
}
347. 前 K 個高頻元素
中等
給定一個非空的整數數組,返回其中出現頻率前 *k* 高的元素。
示例 1:
輸入: nums = [1,1,1,2,2,3], k = 2
輸出: [1,2]
示例 2:
輸入: nums = [1], k = 1
輸出: [1]
提示:
- 你可以假設給定的 k 總是合理的,且 1 ≤ k ≤ 數組中不相同的元素的個數。
- 你的算法的時間復雜度必須優於 O(n log n) , n 是數組的大小。
- 題目數據保證答案唯一,換句話說,數組中前 k 個高頻元素的集合是唯一的。
- 你可以按任意順序返回答案。
// 設置若干個桶,每個桶存儲出現頻率相同的數。桶的下標表示數出現的頻率,即第 i 個桶中存儲的數出現的頻率為 i。
// 把數都放到桶之后,從后向前遍歷桶,最先得到的 k 個數就是出現頻率最多的的 k 個數。
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer,Integer> map = new HashMap<>();
for (int num : nums)
map.put(num,map.getOrDefault(num,0)+1); //數字頻數哈希表
List<Integer>[] buckets = new LinkedList[nums.length+1];
for (Integer num : map.keySet()){
int freq = map.get(num);
if (buckets[freq] == null) //沒初始化=>沒有內存=>沒法add
buckets[freq] = new LinkedList<>();
buckets[freq].add(num); //放到對應頻數的桶里
}
int[] res = new int[k];
int index = 0;
for (int i = buckets.length-1; i > 0 && index < k; i--) {
if (buckets[i] == null) continue;
for (Integer num : buckets[i])
res[index++] = num;
}
return res;
}
}
451. 根據字符出現頻率排序
中等
給定一個字符串,請將字符串里的字符按照出現的頻率降序排列。
示例 1:
輸入:
"tree"
輸出:
"eert"
解釋:
'e'出現兩次,'r'和't'都只出現一次。
因此'e'必須出現在'r'和't'之前。此外,"eetr"也是一個有效的答案。
示例 2:
輸入:
"cccaaa"
輸出:
"cccaaa"
解釋:
'c'和'a'都出現三次。此外,"aaaccc"也是有效的答案。
注意"cacaca"是不正確的,因為相同的字母必須放在一起。
示例 3:
輸入:
"Aabb"
輸出:
"bbAa"
解釋:
此外,"bbaA"也是一個有效的答案,但"Aabb"是不正確的。
注意'A'和'a'被認為是兩種不同的字符。
class Solution {
public String frequencySort(String s) {
char[] chars = s.toCharArray();
Map<Character,Integer> map = new HashMap<>();
for (char aChar : chars)
map.put(aChar,map.getOrDefault(aChar,0)+1);
List<Character>[] buckets = new LinkedList[chars.length+1];
for (Character c : map.keySet()) {
int freq = map.get(c);
if (buckets[freq] == null) buckets[freq] = new LinkedList<>();
buckets[freq].add(c);
}
StringBuilder res = new StringBuilder();
for (int i = buckets.length - 1; i > 0; i--) {
if (buckets[i] == null) continue;
for (Character c : buckets[i]) {
for (int j = 0; j < i; j++) res.append(c);
if (res.length() == chars.length) break;
}
}
return res.toString();
}
}
75. 顏色分類
中等
給定一個包含紅色、白色和藍色,一共 n 個元素的數組,原地對它們進行排序,使得相同顏色的元素相鄰,並按照紅色、白色、藍色順序排列。
此題中,我們使用整數 0、 1 和 2 分別表示紅色、白色和藍色。
注意:
不能使用代碼庫中的排序函數來解決這道題。
示例:
輸入: [2,0,2,1,1,0]
輸出: [0,0,1,1,2,2]
進階:
- 一個直觀的解決方案是使用計數排序的兩趟掃描算法。
首先,迭代計算出0、1 和 2 元素的個數,然后按照0、1、2的排序,重寫當前數組。 - 你能想出一個僅使用常數空間的一趟掃描算法嗎?
// 0跟head換,head++;2跟tail換,tail--
// 換就完事了,判斷一樣費時間
// 注意:跟tail換時指針不往前走,因為不知道換個啥回來
class Solution {
public void sortColors(int[] nums) {
int head = 0, curr = 0;
int tail = nums.length - 1;
int tmp;
while (curr <= tail) {
if (nums[curr] == 0) {
tmp = nums[head];
nums[head++] = nums[curr];
nums[curr++] = tmp;
}
else if (nums[curr] == 2) {
tmp = nums[curr];
nums[curr] = nums[tail];
nums[tail--] = tmp;
}
else curr++;
}
}
}
頻率排序
853. 車隊
中等
N
輛車沿着一條車道駛向位於 target
英里之外的共同目的地。
每輛車 i
以恆定的速度 speed[i]
(英里/小時),從初始位置 position[i]
(英里) 沿車道駛向目的地。
一輛車永遠不會超過前面的另一輛車,但它可以追上去,並與前車以相同的速度緊接着行駛。
此時,我們會忽略這兩輛車之間的距離,也就是說,它們被假定處於相同的位置。
車隊 是一些由行駛在相同位置、具有相同速度的車組成的非空集合。注意,一輛車也可以是一個車隊。
即便一輛車在目的地才趕上了一個車隊,它們仍然會被視作是同一個車隊。
會有多少車隊到達目的地?
示例:
輸入:target = 12, position = [10,8,0,5,3], speed = [2,4,1,1,3]
輸出:3
解釋:
從 10 和 8 開始的車會組成一個車隊,它們在 12 處相遇。
從 0 處開始的車無法追上其它車,所以它自己就是一個車隊。
從 5 和 3 開始的車會組成一個車隊,它們在 6 處相遇。
請注意,在到達目的地之前沒有其它車會遇到這些車隊,所以答案是 3。
提示:
0 <= N <= 10 ^ 4
0 < target <= 10 ^ 6
0 < speed[i] <= 10 ^ 6
0 <= position[i] < target
- 所有車的初始位置各不相同。
class Car{ //用類來整合比別的數據結構舒服
int position;
double time;
public Car(int position, double time) {
this.position = position;
this.time = time;
}
}
class Solution {
public int carFleet(int target, int[] position, int[] speed) {
int len = position.length;
Car[] cars = new Car[len];
for (int i = 0; i < len; i++)
cars[i] = new Car(position[i],(double)(target-position[i])/speed[i]);
Arrays.sort(cars,(x,y)->(y.position-x.position)); //按位置的降序
int res = 0;
for (int i = 0; i < len; i++) {
res++;
double head = cars[i].time;
while (i < len && cars[i].time <= head) i++; //在我后邊的,用時小於等於我的,才能追上我,和我同步到達
i--; //for自帶自增,會多加一次,所以減回來
}
return res;
}
}
179. 最大數
中等
給定一組非負整數,重新排列它們的順序使之組成一個最大的整數。
示例 1:
輸入: [10,2]
輸出: 210
示例 2:
輸入: [3,30,34,5,9]
輸出: 9534330
說明: 輸出結果可能非常大,所以你需要返回一個字符串而不是整數。
class Solution {
public String largestNumber(int[] nums) {
//這樣寫會報錯,基本數據類型都不能這么些,所以后邊先把int[]轉成了String[]
//Arrays.sort(nums,(x,y) -> (String.valueOf(y)+String.valueOf(x)).compareTo(String.valueOf(x)+String.valueOf(y));
String[] strs = new String[nums.length];
for(int i = 0; i < nums.length; i++)
strs[i] = String.valueOf(nums[i]);
Arrays.sort(strs, (x, y) -> (y + x).compareTo(x + y));
StringBuilder res = new StringBuilder();
for(String s : strs)
res.append(s);
return res.toString();
}
}
148. 排序鏈表
中等
在 O(n log n) 時間復雜度和常數級空間復雜度下,對鏈表進行排序。
示例 1:
輸入: 4->2->1->3
輸出: 1->2->3->4
示例 2:
輸入: -1->5->3->4->0
輸出: -1->0->3->4->5
class Solution {
public ListNode sortList(ListNode head) {
if (head == null || head.next == null)
return head; //遞歸到頭只有head了,這時候開始merge
ListNode slow = head, fast = head.next;
while (fast != null && fast.next != null){ //二分鏈表
fast = fast.next.next;
slow = slow.next;
}
ListNode head2 = slow.next;
slow.next = null;
return merge(sortList(head),sortList(head2)); //遞歸合並
}
private ListNode merge(ListNode a,ListNode b) { //合並有序鏈表
ListNode node = new ListNode(0);
ListNode p = node;
while (a != null && b != null){
if (a.val < b.val){
p.next = a;
a = a.next;
}else {
p.next = b;
b = b.next;
}
p = p.next;
}
p.next = a != null ? a : b;
return node.next;
}
}
56. 合並區間
中等
給出一個區間的集合,請合並所有重疊的區間。
示例 1:
輸入: [[1,3],[2,6],[8,10],[15,18]]
輸出: [[1,6],[8,10],[15,18]]
解釋: 區間 [1,3] 和 [2,6] 重疊, 將它們合並為 [1,6].
示例 2:
輸入: [[1,4],[4,5]]
輸出: [[1,5]]
解釋: 區間 [1,4] 和 [4,5] 可被視為重疊區間。
class Solution {
public int[][] merge(int[][] intervals) {
if (intervals.length < 2) return intervals;
Arrays.sort(intervals,(a,b)->(a[0]-b[0]));
List<int[]> list = new LinkedList<>();
list.add(intervals[0]);
for (int i = 1; i < intervals.length; i++) {
int tail = list.get(list.size()-1)[1];
if (intervals[i][0] > tail){
list.add(intervals[i]);
}else if (intervals[i][1] > tail){
list.get(list.size()-1)[1] = intervals[i][1];
}
}
int len = list.size();
int[][] res = new int[len][2];
for (int i = 0; i < len; i++) {
res[i] = list.get(i);
}
return res;
}
}