53. 最大子数组和
class Solution {
public:
int maxSubArray(vector<int>& nums) {
// 1. dp[i] 包括下标i(以nums[i]为结尾)的最大连续子序列和为dp[i]
// 2. dp[i] = max(nums[i],dp[i - 1] + nums[i]); dp[i - 1] + nums[i],即:nums[i]加入当前连续子序列和
// nums[i],即:从头开始计算当前连续子序列和
// 3. 从递推公式可以看出来dp[i]是依赖于dp[i - 1]的状态,dp[0]就是递推公式的基础。
// 4. 1 - n
// 5. 方程
if (nums.size() == 0) return 0;
vector<int> dp(nums.size(),0);
dp[0] = nums[0];
int result = dp[0];
for (int i = 1; i < nums.size(); i++) {
dp[i] = max(dp[i - 1] + nums[i],nums[i]);
if (result < dp[i]) {result = dp[i];}
}
return result;
}
};
时间复杂度: O ( N ) O(N) O(N)
空间复杂度: O ( 1 ) O(1) O(1)
142. 环形链表 II
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
if (head == nullptr || head -> next == nullptr) return nullptr;
while (fast && fast -> next) {
fast = fast -> next -> next;
slow = slow -> next;
if (fast == slow) {
ListNode* index1 = slow;
ListNode* index2 = head;
while (index1 != index2) {
index1 = index1 -> next;
index2 = index2 -> next;
}
return index2;
}
}
return nullptr;
}
};
时间复杂度: O ( N ) O(N) O(N)
空间复杂度: O ( 1 ) O(1) O(1)
2. 两数相加
/**
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode* dummy = new ListNode(-1);
ListNode* cur = dummy;
ListNode* cur1 = l1;
ListNode* cur2 = l2;
int t = 0;
while (cur1 || cur2 || t) {
if (cur1) {
t += cur1 -> val;
cur1 = cur1 -> next;
}
if (cur2) {
t += cur2->val;
cur2 = cur2 -> next;
}
cur -> next = new ListNode(t % 10);
cur = cur -> next;
t /= 10;
}
return dummy -> next;
}
};
时间复杂度: O ( m a x ( m , n ) ) O(max(m,n)) O(max(m,n)),其中 m和 n分别为两个链表的长度。我们要遍历两个链表的全部位置,而处理每个位置只需要 O(1) 的时间。
空间复杂度: O ( 1 ) O(1) O(1)
19. 删除链表的倒数第 N 个结点
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
if (head == nullptr || n == 0) return nullptr;
ListNode* dummy = new ListNode(-1);
dummy -> next = head;
ListNode* x = findListNode(dummy,n + 1);
x -> next = x -> next -> next;
return dummy -> next;
}
ListNode* findListNode(ListNode* head,int k) {
ListNode* slow = head;
ListNode* fast = head;
while (k -- && fast) {
fast = fast -> next;
}
while (fast) {
slow = slow -> next;
fast = fast -> next;
}
return slow;
}
};
时间复杂度: O ( L ) O(L) O(L),其中 L 是链表的长度。
空间复杂度: O ( 1 ) O(1) O(1)
21. 合并两个有序链表
lass Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
if (list1 == nullptr) return list2;
if (list2 == nullptr) return list1;
ListNode* dummy = new ListNode(-1);
ListNode* cur = dummy;
ListNode* cur1 = list1;
ListNode* cur2 = list2;
while (cur1 && cur2) {
if (cur1 -> val > cur2 -> val) {
cur -> next = cur2;
cur2 = cur2 -> next;
}
else {
cur -> next = cur1;
cur1 = cur1 -> next;
}
cur = cur -> next;
}
if (cur1) cur -> next = cur1;
if (cur2) cur -> next = cur2;
return dummy -> next;
}
};
时间复杂度: O ( n + m ) O(n+m) O(n+m),其中 n 和 m 分别为两个链表的长度。因为每次循环迭代中,l1 和 l2 只有一个元素会被放进合并链表中, 因此 while 循环的次数不会超过两个链表的长度之和。所有其他操作的时间复杂度都是常数级别的,因此总的时间复杂度为 O(n+m)。
空间复杂度: O ( 1 ) O(1) O(1)。我们只需要常数的空间存放若干变量。
102. 二叉树的层序遍历
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
queue<TreeNode*> q;
if (root == nullptr) return res;
q.push(root);
while (q.size()) {
vector<int> temp;
int size = q.size();
for (int i = 0; i < size; i++) {
auto t = q.front();
temp.push_back(t -> val);
q.pop();
if (t -> left) q.push(t -> left);
if (t -> right) q.push(t -> right);
}
res.push_back(temp);
}
return res;
}
};
104. 二叉树的最大深度
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int maxDepth(TreeNode* root) {
if(root == nullptr) return 0;
return max(maxDepth(root -> left),maxDepth(root -> right)) + 1;
}
};
17. 电话号码的字母组合
class Solution {
public:
const string letterMap[10] = {
"", // 0
"", // 1
"abc", // 2
"def", // 3
"ghi", // 4
"jkl", // 5
"mno", // 6
"pqrs", // 7
"tuv", // 8
"wxyz", // 9
};
vector<string> result;
string s;
void process(int index,string digits) {
if (index == digits.size()) {
result.push_back(s);
return ;
}
int digit = digits[index] - '0';
string letters = letterMap[digit];
for (int i = 0; i < letters.size(); i++) {
s.push_back(letters[i]);
process(index + 1,digits);
s.pop_back();
}
}
vector<string> letterCombinations(string digits) {
if (digits.size() == 0) {
return result;
}
process(0,digits);
return result;
}
};
时间复杂度: O ( 3 m × 4 n ) O(3^m×4^n) O(3m×4n)
空间复杂度: O ( m + n ) O(m+n) O(m+n),其中 m 是输入中对应 3 个字母的数字个数,n 是输入中对应 4 个字母的数字个数,m+n是输入数字的总个数。除了返回值以外,空间复杂度主要取决于哈希表以及回溯过程中的递归调用层数,哈希表的大小与输入无关,可以看成常数,递归调用层数最大为 m+n。
46. 全排列
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
void process(int index,vector<int>& nums,vector<bool> &used) {
if (path.size() == nums.size()) {
res.push_back(path);
return;
}
for (int i = 0; i < nums.size(); i++) {
if (used[i] == false) {
used[i] = true;
path.push_back(nums[i]);
process(index + 1,nums,used);
used[i] = false;
path.pop_back();
}
}
}
vector<vector<int>> permute(vector<int>& nums) {
if (nums.size() == 0) return res;
vector<bool> used(nums.size(),false);
process(0,nums,used);
return res;
}
};
时间复杂度: O ( N ! N ) O(N!N) O(N!N): N为数组 nums 的长度;时间复杂度和数组排列的方案数成线性关系,即复杂度为 O(N!);数组拼接操作 join() 使用 O(N);因此总体时间复杂度为 O(N!N) 。
空间复杂度: O ( N ) O(N) O(N) : 全排列的递归深度为 N ,系统累计使用栈空间大小为 O(N) 。