LeetCode解题总结(1)
序
最近在对以前学过做过的东西做一些总结和回顾,为了检验学习成果和查漏补缺,开启了一段刷题之路。
1. Two Sum
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
思路
看完描述后,最容易想到的是暴力计算的思路,对每个数,用target减去这个数,得到一个需要用来相加的数字,然后遍历除自己外的所有数字,找出是否满足,如果满足,就返回这两个数的位置。此时,因为对每个数都要进行一次遍历,所以时间复杂度为O(n^2),不需要额外空间,空间复杂度为O(1)。
但是显然这样做是不好的,想到解唯一且重复的计算很多,所以用空间换时间的做法,每次相减后直接把结果记录下来,如果碰到一个数跟之前记录的需要的结果相同,即为解:
此时,只需要一次遍历即可,时间复杂度O(n),空间复杂度O(n)
class Solution { public: vector<int> twoSum(vector<int>& nums, int target) { unordered_map<int, int> s; for (int i = 0; i < nums.size(); ++i) { if (s.count(target - nums[i])) { return {s[target - nums[i]], i}; } s[nums[i]] = i; } vector<int> res; return res; } };
2. Add Two Numbers
You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
思路
这道题虽然是链表,但根据描述其实可以看出来就是一个把数字反过来按照正常做加法计算的题目,那其实就是一个遍历相加再加上进位的过程。时间复杂度O(max(m,n)),空间复杂度O(max(m,n)):
class Solution { public: ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { int add = 0; if (!l1 && !l2) return nullptr; ListNode *begin = new ListNode(0); ListNode *now = begin; while(l1 || l2 || add > 0) { int a = 0; int b = 0; if (l1) { a = l1->val; l1 = l1->next; } if (l2) { b = l2->val; l2 = l2->next; } now->val = a + b + add; add = 0; if (now->val > 9) { now->val = now->val - 10; add = 1; } if (l1 || l2 || add > 0) { now->next = new ListNode(0); now = now->next; } } return begin; } };
对链表题有个套路,先新建一个节点,指向链表头,那么所有的操作都可以统一为一样的,减少一些判断。
class Solution { public: ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { int add = 0; ListNode *begin = new ListNode(0); ListNode *now = begin; while(l1 || l2 || add) { if (l1) { add += l1->val; l1 = l1->next; } if (l2) { add += l2->val; l2 = l2->next; } now->next = new ListNode(add % 10); add /= 10; now = now->next; } return begin->next; } };
3. Longest Substring Without Repeating Characters
Given a string, find the length of the longest substring without repeating characters.
Input: "abcabcbb" Output: 3 Explanation: The answer is "abc", with the length of 3.
思路
这道题看到之后首先浮现的依然是最粗暴的遍历算法,每个往后数,直到重复,然后用一个唯一的集合来记录数过的字符,开始想的是用一个 map<char, int> 来记录字符位置,又由于char的大小只有256,就可以换成 vector
然后再想到通过滑动窗口来优化,begin为当前子串开始位置,i为结尾位置,如果从begin到i中间没有重复字符,i就继续向右移动,如果i遇到有重复字符串,可以理解为s[i] 与从 s[begin] 到 s[i-1] 中的字符有重复,而 s[begin] 到 s[i-1] 中的字符没有重复,所以从重复的位置后一位开始到i处也应该是没有重复的,此时下一个子串begin位置就移动到了重复位置+1的位置上,而i无需往前移动,继续往后比较就可以了,同样使用上面方法提到的 vector
class Solution { public: int lengthOfLongestSubstring(string s) { vector<int> posMap(256, -1); int max1 = 0; int begin = 0; int i = 0; for (; i < s.size(); ++i) { auto& ch = s[i]; if (posMap[ch] >= 0) { begin = max(posMap[ch] + 1, begin); } max1 = max(max1, i - begin + 1); posMap[ch] = i; } return max(max1, i - begin); } };
4. Median of Two Sorted Arrays
There are two sorted arrays nums1 and nums2 of size m and n respectively.
Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
You may assume nums1 and nums2 cannot be both empty.
Example 1:
nums1 = [1, 3] nums2 = [2] The median is 2.0
Example 2:
nums1 = [1, 2] nums2 = [3, 4] The median is (2 + 3)/2 = 2.5
思路
阅读题目后,知道需要求解的其实就是首先将两个有序数组变为一个有序数组,然后找出中间的值。分析可知,如果两个数组数字总数为基数,中间值就是中间的数,如果总数为偶数,中间值是中间的数与-1位置的数的平均。计算之后遍历两个数组,每次从中取出最小的数,直到中位数位置。此时,时间复杂度为O((m+n)/2),空间复杂度O(1)
class Solution { public: double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { int carry = (nums1.size() + nums2.size()) % 2; int countN = (nums1.size() + nums2.size() + 1) / 2; auto it1 = nums1.begin(); auto it2 = nums2.begin(); double num = 0; for (int i = 0; i < countN; ++i) { if (it1 == nums1.end() || (it2 != nums2.end() && *it2 < *it1)) { num = *it2; ++it2; } else { num = *it1; ++it1; } } if (carry == 0) { if (it1 == nums1.end() || (it2 != nums2.end() && *it2 < *it1)) { num += *it2; } else { num += *it1; } num /= 2; } return num; } };
5. Longest Palindromic Substring
Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.
思路
看到题目后我一开始想到的是回文数从中间位置开始,往两边的字符是一样的,所以直接对每一个字符进行判断,看其最长长度,同时,如果相邻两个字符相等,一定是在此回文数串中,所以遇到相邻相同字符可以直接看作一个整体去处理。此时,时间复杂度应该是O((n^2) / 2),空间复杂度O(1)
class Solution { public: string longestPalindrome(string s) { int size = s.size(); if (size < 2) return s; int beginIdx = 0; int endIdx = 0; int i = 0; int j = 0; for (; i < size; ++i) { j = i; while (i < size && s[j] == s[i + 1]) ++i; int k = i; if (i < size - 1) { while (k < size - 1 && j > 0 && s[j - 1] == s[k + 1]) { --j; ++k; } } if (endIdx - beginIdx < k - j) { beginIdx = j; endIdx = k; } } return s.substr(beginIdx, endIdx - beginIdx + 1); } };