連接:https://leetcode.com/tag/sort/html
【56】Merge Intervals (2019年1月26日,谷歌tag複習)算法
合併區間數組
Input: [[1,3],[2,6],[8,10],[15,18]] Output: [[1,6],[8,10],[15,18]] Explanation: Since intervals [1,3] and [2,6] overlaps, merge them into [1,6].
題解:先按照interval的begin從小到大sort一下,而後順序遍歷,能合併的就合併,不能合併的就加入一個新的interval。app
1 /** 2 * Definition for an interval. 3 * struct Interval { 4 * int start; 5 * int end; 6 * Interval() : start(0), end(0) {} 7 * Interval(int s, int e) : start(s), end(e) {} 8 * }; 9 */ 10 //time complexity: O(nlogn) 11 class Solution { 12 public: 13 vector<Interval> merge(vector<Interval>& intervals) { 14 sort(intervals.begin(), intervals.end(), cmp); 15 vector<Interval> ret; 16 for (auto inter : intervals) { 17 if (ret.empty()) { 18 ret.push_back(inter); 19 continue; 20 } 21 if (inter.start > ret.back().end) { 22 ret.push_back(inter); 23 } else { 24 ret.back().end = max(inter.end, ret.back().end); 25 } 26 } 27 return ret; 28 } 29 static bool cmp (const Interval& inter1, const Interval& inter2) { 30 return inter1.start < inter2.start; 31 } 32 };
【57】Insert Interval (2019年1月26日,谷歌tag複習)dom
Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessary).ide
You may assume that the intervals were initially sorted according to their start times函數
Input: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]優化
Output: [[1,2],[3,10],[12,16]]spa
Explanation: Because the new interval [4,8] overlaps with [3,5],[6,7],[8,10].指針
題解:先按照插入排序把須要插入的interval放在原來intervals中合適的位置,而後合併區間。
1 /** 2 * Definition for an interval. 3 * struct Interval { 4 * int start; 5 * int end; 6 * Interval() : start(0), end(0) {} 7 * Interval(int s, int e) : start(s), end(e) {} 8 * }; 9 */ 10 class Solution { 11 public: 12 vector<Interval> insert(vector<Interval>& intervals, Interval newInterval) { 13 const int n = intervals.size(); 14 int i = 0; 15 for (; i < n; ++i) { 16 if (intervals[i].start >newInterval.start) { 17 auto iter = intervals.begin() + i; 18 intervals.insert(iter, newInterval); 19 break; 20 } 21 } 22 if (i == n) { 23 intervals.push_back(newInterval); 24 } 25 vector<Interval> ret; 26 for (auto interval : intervals) { 27 if (ret.empty() || ret.back().end < interval.start) { 28 ret.push_back(interval); 29 } else { 30 ret.back().end = max(interval.end, ret.back().end); 31 } 32 } 33 return ret; 34 } 35 };
【75】Sort Colors (2018年12月11日,wiggle sort專題複習,荷蘭國旗問題)
給了一個數組,包含重複的 0,1,2 三種數字,實現一種操做,能用 one pass,O(1) 的space把這個數組變成0,1,2的順序數組。
題解:用三根指針,left,right,mid。最後的時候 left 指向 1 的第一個元素,right 指向 1 的最後一個元素。
2019年1月20日補充,left一開始在最左邊,right一開始在最右邊,咱們有一個可以往前移動的指針叫作point或者mid,咱們想用mid指針遍歷過整段的1,因此若是當前的mid指針指向的是0的話,咱們想把這個0放到最前面去,因此把這個0和前面的left作交換,left++,mid++。若是當前的mid指針指向的是 2 的話,咱們把它和後面的right作交換,--right,可是這裏不能++mid,由於有可能原來的 right位置就是 2,交換完了以後 mid 指向的仍是 2.
1 //荷蘭國旗問題 2 class Solution { 3 public: 4 void sortColors(vector<int>& nums) { 5 const int n = nums.size(); 6 int left = 0, mid = 0, right = n-1; 7 while (mid <= right) { 8 if (nums[mid] == 0) { 9 swap(nums[left++], nums[mid++]); 10 } else if (nums[mid] == 2) { 11 swap(nums[right--], nums[mid]); 12 } else { 13 mid++; 14 } 15 } 16 return; 17 } 18 };
【147】Insertion Sort List
【148】Sort List
【164】Maximum Gap
【179】Largest Number (2019年2月23日,M)
給了一個整數的數組,要求返回一個字符串,這個字符串由整數數組的元素拼接而成。每一個元素只能用一次。求這個字符串轉換成數字的最大值。
Input: Output: "[3,30,34,5,9]9534330"
題解:咱們想象一下比較兩個數,3,和 30,這兩個數應該誰在前誰在後,若是3在前面,30在後面,組成的數字是330,若是30在前面,3在後面,組成的數字是303。咱們判定330確定大於303。因此咱們算法以下,把整數數組排列成字符串,而且給新的字符串數組排序。排序的規則咱們本身定義,s1 + s2 > s2 + s1 返回true。
1 class Solution { 2 public: 3 string largestNumber(vector<int>& nums) { 4 const int n = nums.size(); 5 vector<string> strs(n); 6 for (int i = 0; i < n; ++i) { 7 strs[i] = to_string(nums[i]); 8 } 9 sort(strs.begin(), strs.end(), cmp); 10 string res; 11 for (auto& s : strs) { 12 res += s; 13 } 14 while (res.size() > 1 && res[0] == '0') { 15 res = res.substr(1); 16 } 17 return res; 18 } 19 static bool cmp(const string& s1, const string& s2) { 20 string t1 = s1 + s2, t2 = s2 + s1; 21 return t1 > t2; 22 } 23 };
【242】Valid Anagram
【252】Meeting Rooms (2018年11月22日,爲了衝題量)
題意就是給了一個數組,數組裏面的每一個元素表明一個會議的開始時間和結束時間。問能不能用一個會議室安排下全部的會議。
題解:這題好像之前就作過相似的線段題,先給數組排序,用結束時間從小到大排序,若是結束時間相同,就按照開始時間從小到大排序。而後遍歷數組,看前一個元素的結束時間是否小於等於當前元素的開始時間。 都知足條件返回 true,有一個不知足條件的返回false。
1 /** 2 * Definition for an interval. 3 * struct Interval { 4 * int start; 5 * int end; 6 * Interval() : start(0), end(0) {} 7 * Interval(int s, int e) : start(s), end(e) {} 8 * }; 9 */ 10 class Solution { 11 public: 12 bool canAttendMeetings(vector<Interval>& intervals) { 13 if (intervals.empty()) {return true;} 14 sort(intervals.begin(), intervals.end(), cmp); 15 for (auto i = 0; i < intervals.size()-1; ++i) { 16 if (intervals[i].end > intervals[i+1].start) { 17 return false; 18 } 19 } 20 return true; 21 } 22 static bool cmp(const Interval& a, const Interval& b) { 23 if (a.end != b.end) { 24 return a.end < b.end; 25 } 26 return a.start < b.start; 27 } 28 };
【253】Meeting Rooms II (2018年11月22日,爲了衝題量)
題意是252的升級版,給了一個數組,數組裏面的每一個元素表明一個會議的開始時間和結束時間,問想安排下全部的會議,至少須要多少個會議室。
題解:仍是先排序。此次可能按照結束時間從大到小排序,結束時間相同的時候就按照開始時間從大到小排序,或者從小到大排序而後從後往前遍歷均可以。用一個map記錄key是會議室編號,value是這個會議室的下一個會議的開始時間。若是當前會議的結束時間小於等於下一個會議的開始時間就能放在這個會議室裏面,否則須要從新開一個會議室。有一種case須要注意,若是我按照會議結束時間從小到大排序而後順序安排,有可能有一個會議室的時間軸兩個會議之間會有一段很大的gap,這個gap可能從新安排就能減小會議室的整體數量。按照結束時間從大到小排序能保證能一個會議室中間的gap不會很大。
1 /** 2 * Definition for an interval. 3 * struct Interval { 4 * int start; 5 * int end; 6 * Interval() : start(0), end(0) {} 7 * Interval(int s, int e) : start(s), end(e) {} 8 * }; 9 */ 10 class Solution { 11 public: 12 int minMeetingRooms(vector<Interval>& intervals) { 13 if (intervals.empty()) {return 0;} 14 const int n = intervals.size(); 15 sort(intervals.begin(), intervals.end(), cmp); 16 int ret = 1; 17 map<int, int> mp; //roomNumber -> starttime 18 mp[ret] = intervals[0].start; 19 for (int i = 1; i < n; ++i) { 20 bool find = false; 21 for (auto& e : mp) { 22 if (e.second >= intervals[i].end) { 23 find = true; 24 e.second = intervals[i].start; 25 break; 26 } 27 } 28 if (!find) { 29 mp[++ret] = intervals[i].start; 30 } 31 } 32 return ret; 33 } 34 static bool cmp(const Interval& a, const Interval& b) { 35 if (a.end != b.end) { 36 return a.end > b.end; 37 } 38 return a.start > b.start; 39 } 40 };
這題還有個 greedy 和 heap 的標籤,思想就是 greedy,heap怎麼解不懂啊。
【274】H-Index
【280】Wiggle Sort (2018年12月11日,wiggle sort專題)
Given an unsorted array nums
, reorder it in-place such that nums[0] <= nums[1] >= nums[2] <= nums[3]...
.
Example: Input: nums = [3,5,2,1,6,4] Output: One possible answer is [3,5,1,6,2,4]
題解:依次比較相鄰的兩個數,不符合條件的就作交換。
1 class Solution { 2 public: 3 void wiggleSort(vector<int>& nums) { 4 const int n = nums.size(); 5 for (int i = 1; i < n; ++i) { 6 if (i & 0x1 && nums[i] < nums[i-1]) { 7 swap(nums[i], nums[i-1]); 8 } else if (i % 2 == 0 && nums[i] > nums[i-1]) { 9 swap(nums[i], nums[i-1]); 10 } 11 } 12 return; 13 } 14 };
2019年2月18日補充,時間複雜度是O(N)
【296】Best Meeting Point (2018年11月22日,開始作 hard 題)
給了一個二維的 0/1 矩陣grid, grid[i][j] = 1 表明 1 位置上有我的,如今矩陣上至少有兩我的,這幾我的想挑一個點 (x, y) 相會,問矩陣上的哪一個點到這幾我的的曼哈頓距離和最近,返回最近的距離之和。
曼哈頓距離的公式是 distance(p1, p2) = |p2.x - p1.x| + |p2.y - p1.y|
.
題解:我一開始就暴力了,時間複雜度是 O(n*m*k),而後竟然卡着時間過了orz,只 beats 了 1.15%,尷尬。下面附上尷尬的強行解。
1 class Solution { 2 public: 3 int minTotalDistance(vector<vector<int>>& grid) { 4 const int n = grid.size(); 5 if (n == 0) {return 0;} 6 const int m = grid[0].size(); 7 if (m == 0) {return 0;} 8 vector<vector<int>> people; 9 for (int i = 0; i < n; ++i) { 10 for (int j = 0; j < m; ++j) { 11 if (grid[i][j]) { 12 people.push_back(vector<int>{i, j}); 13 } 14 } 15 } 16 int ret = INT_MAX; 17 for (int i = 0; i < n; ++i) { 18 for (int j = 0; j < m; ++j) { 19 int summ = 0; 20 for (int k = 0; k < people.size(); ++k) { 21 summ += abs(i - people[k][0]) + abs(j - people[k][1]); 22 if (summ > ret) {break;} 23 } 24 ret = min(summ, ret); 25 } 26 } 27 return ret; 28 } 29 };
咱們下面來看一下優秀的解法們:咱們能夠先分析一下一維數組的狀況,咱們假設這個數組是 [1,0,0,1,0,0,0,1],會面的位置選在第二個 1 的位置距離和最小。因此這個結論就是一維數組是選在前綴和的中位數上,median,若是是偶數個 1,好比 [1,1,0,1,1], 這個位置選在下標 1, 2, 3上均可以。由於是求曼哈頓距離,因此徹底能夠行和列分離,分解成兩個一維數組的狀況。咱們首先對矩陣的行和列進行累加,把一個矩陣拍成一維數組,而後結果就是兩個一維數組的距離之和。時間複雜度是(m*n*log(nm))
1 class Solution { 2 public: 3 int minTotalDistance(vector<vector<int>>& grid) { 4 const int n = grid.size(); 5 if (n == 0) {return 0;} 6 const int m = grid[0].size(); 7 if (m == 0) {return 0;} 8 vector<int> rows(m, 0), cols(n, 0); 9 for (int j = 0; j < m; ++j) { 10 for (int i = 0; i < n; ++i) { 11 if (grid[i][j]) { 12 rows[j] += 1; 13 cols[i] += 1; 14 } 15 } 16 } 17 int ret = cope(rows) + cope(cols); 18 return ret; 19 } 20 int cope(const vector<int>& nums) { 21 const int n = nums.size(); 22 vector<int> summ = nums; 23 for (int i = 1; i < n; ++i) { 24 summ[i] += summ[i-1]; 25 } 26 int median = (summ[n-1] + 1) / 2; 27 auto iter = lower_bound(summ.begin(), summ.end(), median); 28 int index = distance(summ.begin(), iter); 29 int ret = 0; 30 for (int i = 0; i < nums.size(); ++i) { 31 ret += abs(index - i) * nums[i]; 32 } 33 /* 34 print("nums", nums); 35 print("summ", summ); 36 printf("median = %d, index = %d, ret = %d \n", median, index, ret); 37 */ 38 return ret; 39 } 40 void print(const string name, const vector<int>& nums) { 41 printf("%s: ", name.c_str()); 42 for (auto n : nums) { 43 printf("%d ", n); 44 } 45 printf("\n"); 46 } 47 48 };
還能夠更加優化,見solution的最後一個解法,它能把時間複雜度搞成 O(mn)。唉我不想看了,
【324】Wiggle Sort II (2019年2月20日)
擺動排序。Given an unsorted array nums
, reorder it such that nums[0] < nums[1] > nums[2] < nums[3]...
.
Example 1: Input: nums = [1, 5, 1, 1, 6, 4] Output: One possible answer is [1, 4, 1, 5, 1, 6]. Example 2: Input: nums = [1, 3, 2, 2, 3, 1] Output: One possible answer is [2, 3, 1, 3, 1, 2].
Can you do it in O(n) time and/or in-place with O(1) extra space?
題解:咱們先把數組排序,而後找到中位數。而後咱們用中位數把數組分紅兩半,若是是奇數長度,前半段長一點。而後咱們用兩根指針,同時從兩段數組的末尾開始掃描。加入一個新的數組。這樣就能保證前半段的數字必定小於後半段的數字。
這種解法時間複雜度是O(nlogn),空間複雜度是O(n)
1 class Solution { 2 public: 3 void wiggleSort(vector<int>& nums) { 4 int n = nums.size(); 5 if (n == 0) {return;} 6 sort(nums.begin(), nums.end()); 7 int k = (n-1)/2; 8 int p1 = k, p2 = n-1; 9 vector<int> ret(n); 10 int idx = 0; 11 while (idx < n) { 12 ret[idx++] = nums[p1--]; 13 if (idx >= n) {break;} 14 ret[idx++] = nums[p2--]; 15 } 16 nums = ret; 17 } 18 };
【349】Intersection of Two Arrays (2018年11月6日,算法羣相關題)
給了兩個數組,返回他們交疊的元素,若是有重複元素的話,只返回一個就好了。
hash-table 裏面有這題,我就不重複寫了。hash-table:http://www.javashuo.com/article/p-mjknibky-mq.html
【350】Intersection of Two Arrays II (2018年11月6日,算法羣)
給了兩個數組,返回他們全部交疊的元素,元素能夠任意順序返回,可是若是一個元素在A,B數組中都出現屢次,須要返回公共的屢次。
hash-table 裏面有這題,我就不重複寫了。hash-table:http://www.javashuo.com/article/p-mjknibky-mq.html
【524】Longest Word in Dictionary through Deleting (2019年2月23日)
給了一個字符串s,和一個 wordlist,找出list裏面是 s 的子序列而且最長的一個單詞,若是有兩個單詞相同長度,而且都是s的子序列,那麼返回 lexicographcal order 小的那個。
Input: s = "abpcplea", d = ["ale","apple","monkey","plea"] Output: "apple"
題解:咱們須要依次判斷列表中的單詞是否是 s 的子序列。須要寫一個 match 函數,而後依次判斷能夠,或者把列表排序後再判斷也能夠。
1 class Solution { 2 public: 3 string findLongestWord(string s, vector<string>& d) { 4 const int n = d.size(); 5 //sort(d.begin(), d.end(), cmp); 6 string res = ""; 7 for (auto& t : d) { 8 if (match(s, t)) { 9 if (t.size() > res.size()) {res = t;} 10 if (t.size() == res.size()) {res = min(t, res);} 11 } 12 } 13 return res; 14 } 15 static bool cmp(const string& s1, const string& s2) { 16 if (s1.size() == s2.size()) { 17 return s1 < s2; 18 } 19 return s1.size() > s2.size(); 20 } 21 bool match(const string& s, const string& t) { 22 if (s.size() < t.size()) {return false;} 23 const int ssize = s.size(), tsize = t.size(); 24 int idx = 0; 25 for (int i = 0; i < ssize; ++i) { 26 if (idx < tsize && s[i] == t[idx]) { 27 ++idx; 28 } 29 // if (idx == tsize) {return true;} 30 } 31 return idx == tsize; 32 } 33 };
【527】Word Abbreviation
【710】Random Pick with Blacklist
【767】Reorganize String