LeetCode-Hot100 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class  Solution  {public :    vector<int > twoSum (vector<int >& nums, int  target)   {         unordered_map<int , int > res;         for (int  i = 0 ; i < nums.size (); i ++ ) {             auto  it = res.find (target - nums[i]);             if (it != res.end ()) {                 return  {it -> second, i};             }             res[nums[i]] = i;         }         return  {};     } }; 
主要还是对哈希表不熟悉,可参考c++中unordered_map的用法的详述(包含unordered_map和map的区别)_unorder map-CSDN博客 
1 2 3 4 5 6 7 8 9 10 11 12 class  Solution  {public :    void  moveZeroes (vector<int >& nums)           for (int  i = 0 , j = 0 ; i < nums.size ();) {             if (nums[i] != 0 ) {                 swap (nums[i], nums[j]);                 j ++ ;             }             i ++ ;         }     } }; 
一开始以为是在头尾各设置两个指针,结果发现数组内的非零元素顺序变了。应该是开头设置两个指针,然后让其分别指向零和非零元素,这样的双指针算法是可行的。或者可以让非零元素不断向左覆盖,再在最后补零。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class  Solution  {public :    vector<vector<string>> groupAnagrams (vector<string>& strs) {         unordered_map<string, vector<string>> res1;         for (int  i = 0 ; i < strs.size (); i ++ ) {             string str_s = strs[i];             sort (strs[i].begin (), strs[i].end ());             res1[strs[i]].push_back (str_s);         }         vector<vector<string>> res2;         for (auto  it = res1. begin (); it != res1. end (); it ++ ) {             res2. push_back (it -> second);         }         return  res2;     } }; 
一开始想的是用unordered_set(),后来发现有ab、aab这样的情况就会出错;经观察可以发现,异位词排序后的词刚好可以作为哈希表的键,所以用哈希表做了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class  Solution  {public :    int  longestConsecutive (vector<int >& nums)           unordered_set<int > num_set;         for (int  &n : nums) {             num_set.insert (n);         }         int  length = 0 ;         for (const  int & n : num_set) {             int  cur = 0 ;             int  num = n;             if (num_set.count (num - 1 ) == 0 ) {                 while (num_set.count (num)) {                     cur ++ ;                     num = num + 1 ;                 }                 length = max (length, cur);             }         }         return  length;     } }; 
这题的题目没太搞懂,官方题解是直接去重的,也就是说不考虑重复元素,比如1 2 3 3 3 4 5就应该返回5,而不是7;另外这题的居然用排序比哈希表还快;哈希的核心就是可以用O(1)的时间复杂度来查找哈希集合中的元素,然后根据本题的逻辑进一步优化——即每次只让集合中没有x - 1的x进入循环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class  Solution  {public:     vector<vector<int >> threeSum(vector<int >& nums) {         sort(nums.begin(), nums.end());         vector<vector<int >> res;         for (int  i = 0 ; i < nums.size(); i ++ ) {             if (i == 0  || nums[i] != nums[i - 1 ]) {                 int  target = -nums[i];                 int  l = i + 1 , r = nums.size() - 1 ;                 while (l < r) {                     int  sum  = nums[l] + nums[r];                     if (sum  == target) {                         res.push_back({nums[i], nums[l], nums[r]});                         l ++;                         r -- ;                         while (l < r && nums[l] == nums[l - 1 ]) l ++;                         while (l < r && nums[r] == nums[r + 1 ]) r --;                     }                     else  if (sum  < target) {                         l ++;                     }                     else  {                         r --;                     }                    }                              }         }         return  res;     } }; 
一眼能看出来的方法就是三重循环再加个哈希表去重,但这样的时间和空间复杂度都很高;然后题目提示的方法是排序 + 双指针,双指针算法有快慢指针、对撞指针这两种。根据本题的性质,比较适合对撞指针。经过排序后再进行三重循环,可以避免重复;然后在每重循环中,相邻的两个元素不能相同,可以避免重复。然后发现,二三重循环其实是可以并列的。
当我们需要枚举数组中的两个元素时,如果我们发现随着第一个元素的递增,第二个元素是递减的,那么就可以使用双指针的方法,将枚举的时间复杂度从O(N^2)减少至O(N)。
1 2 3 4 5 6 7 8 9 10 11 12 13 class  Solution  {public :    int  maxArea (vector<int >& height)           int  vol = 0 ;         for (int  i = 0 , j = height.size () - 1 ; i < j;) {             int  v = (j -i) * min (height[i], height[j]);             vol = max (vol, v);             if (height[i] <= height[j]) i ++ ;             else  j -- ;         }         return  vol;     } }; 
暴力的做法就是双重for循环,然后依次求面积。然后这题明显的可以看出来用两个快慢指针,分别从头尾开始移动;最大的难点在于什么时候该移动哪个指针。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class  Solution  {public :    bool  searchMatrix (vector<vector<int >>& matrix, int  target)           if (matrix.empty () || matrix[0 ].empty ()) {             return  false ;         }         int  m = matrix.size ();         int  n = matrix[0 ].size ();         int  i = 0 ;         int  j = n - 1 ;         while (i < m && j >= 0 ) {             if (target == matrix[i][j]) return  true ;             else  if (target < matrix[i][j]) j --;             else  i ++ ;         }         return  false ;     } }; 
暴力解法直接遍历;
对每一行进行二分查找;
Z字形查找,从右上角开始遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 class  Solution  {public :    ListNode* reverseList (ListNode* head)   {         ListNode *curr = new  ListNode ();         ListNode *prev = new  ListNode ();         ListNode *tmp = new  ListNode ();         if (head  != nullptr ) {             curr = head -> next;             prev = head;             prev -> next = nullptr ;         }         else  {             return  nullptr ;         }                  while (curr != nullptr ) {             tmp = curr -> next;             curr -> next = prev;             prev = curr;             curr = tmp;         }         return  prev;     } }; 
利用两个指针从前往后依次逆置相邻的两个结点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class  Solution  {public :    bool  isPalindrome (ListNode* head)           stack<int > s;         ListNode *p = new  ListNode ();         p = head;         while (p != nullptr ) {             s.push (p -> val);             p = p -> next;         }         p = head;         while (p != nullptr ) {             if (p -> val != s.top ()) {                 return  false ;             }             s.pop ();             p = p -> next;          }         return  true ;     } }; 
利用栈结构,先将元素入栈,再依次出栈并且判断链表中的节点元素是否相等;
快慢指针?( 可以将空间复杂度降到O(1) )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class  Solution  {public :    bool  hasCycle (ListNode *head)           unordered_set<ListNode*> res;         while (head != nullptr ) {             if (res.count (head)) {                 return  true ;             }             res.insert (head);             head = head -> next;         }         return  false ;     } }; 
哈希表;
快慢指针,慢指针每次移动一个节点,快指针每次移动两个结点;若存在环,则快慢指针一定会相遇;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 class  Solution  {public :    ListNode *getIntersectionNode (ListNode *headA, ListNode *headB)   {         if (headA == nullptr  || headB == nullptr  ) {             return  nullptr ;         }         ListNode *pA = headA;         ListNode *pB= headB;         while (pA != pB) {             if (pA == nullptr ) {                 pA = headB;             }             else  {                 pA = pA -> next;             }             if (pB == nullptr ) {                 pB = headA;             }             else  {                 pB = pB -> next;             }         }         return  pA;     } }; 
先利用哈希集合存储A中的每个节点,然后遍历B中的节点,若有在哈希集合中出现的则为相交节点;时间复杂度为O(m + n),空间复杂度为O(m);
双指针,设立两个指针分别各自遍历一遍A和B,无论是否相交,最后一定会相遇;时间复杂度为O(m + n),空间复杂度为O(1);