leetcode10月每日一题
文章目录
- leetcode10月每日一题
- 2020/10/5:[四数之和](https://leetcode-cn.com/problems/4sum/)
- 2020/10/7 : [颜色分类](https://leetcode-cn.com/problems/sort-colors/)
- 2020/10/8 :[反转字符串](https://leetcode-cn.com/problems/reverse-string/)
- 2020/10/9 :[环形链表](https://leetcode-cn.com/problems/linked-list-cycle/)
- 2020/10/12 : [二叉搜索树的最小绝对差](https://leetcode-cn.com/problems/minimum-absolute-difference-in-bst/)
- 2020/10/13 : [两两交换链表中的节点](https://leetcode-cn.com/problems/swap-nodes-in-pairs/)
- 2020/10/14 : [查找常用字符](https://leetcode-cn.com/problems/find-common-characters/)
- 2020/10/16 : [有序数组的平方](https://leetcode-cn.com/problems/squares-of-a-sorted-array/)
- 2020/10/18:[删除链表的倒数第N个节点](https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/)
- 2020/10/19:[比较含退格的字符串](https://leetcode-cn.com/problems/backspace-string-compare/)
- 2020/10/20:[重排链表](https://leetcode-cn.com/problems/reorder-list/)
- 2020/10/21:[长按键入](https://leetcode-cn.com/problems/long-pressed-name/)
- 2020/10/22:[划分字母区间](https://leetcode-cn.com/problems/partition-labels/)
- 2020/10/26 : [有多少小于当前数字的数字](https://leetcode-cn.com/problems/how-many-numbers-are-smaller-than-the-current-number/)
- 2020/10/27 : [二叉树的前序遍历](https://leetcode-cn.com/problems/binary-tree-preorder-traversal/)
- 2020/10/28 : [独一无二的出现次数](https://leetcode-cn.com/problems/unique-number-of-occurrences/)
- 2020/10/29 : [求根到叶子节点数字之和](https://leetcode-cn.com/problems/sum-root-to-leaf-numbers/)
- 2020/10/30 :[岛屿的周长](https://leetcode-cn.com/problems/island-perimeter/)
2020/10/5:四数之和
题目 中等
给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
注意:
答案中不可以包含重复的四元组。
示例:
给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。
满足要求的四元组集合为:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]
暴力解法
超时了!!!
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
set<vector<int>> result;
if(nums.empty() || nums.size()<4)
return vector<vector<int>>(result.begin(),result.end());
sort(nums.begin(),nums.end());
for(int i1=0;i1<nums.size()-3;i1++){
for(int i2=i1+1;i2<nums.size()-2;i2++){
for(int i3=i2+1;i3<nums.size()-1;i3++){
for(int i4=i3+1;i4<nums.size();i4++){
if(nums[i1]+nums[i2]+nums[i3]+nums[i4]==target){
vector<int> tmp={nums[i1],nums[i2],nums[i3],nums[i4]};
result.insert(tmp);
}
}
}
}
}
return vector<vector<int>>(result.begin(),result.end());
}
};
- 时间复杂度O(n^4)
- 空间复杂度O(1) 猜的,我也不知道!!
排序+双指针
2020/10/7 : 颜色分类
问题 中等
给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
注意:
不能使用代码库中的排序函数来解决这道题。
示例:
输入: [2,0,2,1,1,0]
输出: [0,0,1,1,2,2]
进阶:
一个直观的解决方案是使用计数排序的两趟扫描算法。
首先,迭代计算出0、1 和 2 元素的个数,然后按照0、1、2的排序,重写当前数组。
你能想出一个仅使用常数空间的一趟扫描算法吗?
非法解决法
使用排序函数
class Solution {
public:
void sortColors(vector<int>& nums) {
sort(nums.begin(),nums.end());
}
};
计数排序
先扫描一遍计算3个颜色各自的数目,在扫描一遍依次赋值。
class Solution {
public:
void sortColors(vector<int>& nums) {
int num0=0,num1=0,num2=0;
for(auto i:nums){
if(i==0)
num0++;
else if(i==1)
num1++;
else
num2++;
}
for(int i=0;i<num0;i++){
nums[i]=0;
}
for(int i=num0;i<num0+num1;i++){
nums[i]=1;
}
for(int i=num0+num1;i<num0+num1+num2;i++){
nums[i]=2;
}
}
};
- 时间复杂度O(n)
- 空间复杂度O(1)
双指针一次遍历
class Solution {
public:
void sortColors(vector<int>& nums) {
int n = nums.size();
int p0 = 0, p1 = 0;
for (int i = 0; i < n; ++i) {
if (nums[i] == 1) {
swap(nums[i], nums[p1]);
++p1;
} else if (nums[i] == 0) {
swap(nums[i], nums[p0]);
if (p0 < p1) {
swap(nums[i], nums[p1]);
}
++p0;
++p1;
}
}
}
};
- 时间复杂度:O(n),其中 nn 是数组nums的长度。
- 空间复杂度:O(1)。
2020/10/8 :反转字符串
问题 简单
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
示例 1:
输入:[“h”,“e”,“l”,“l”,“o”]
输出:[“o”,“l”,“l”,“e”,“h”]
示例 2:
输入:[“H”,“a”,“n”,“n”,“a”,“h”]
输出:[“h”,“a”,“n”,“n”,“a”,“H”]
函数法
抖机灵使用,不建议!这题索然无味!!!!!!!!!!!!!!
class Solution {
public:
void reverseString(vector<char>& s) {
reverse(s.begin(),s.end());
}
};
- 时间复杂度O()
- 空间复杂度O()
双指针法
class Solution {
public:
void reverseString(vector<char>& s) {
int i=0,j=s.size()-1;
while(i<j){
char tmp=s[j];
s[j]=s[i];
s[i]=tmp;
i++;
j--;
}
}
};
- 时间复杂度O(n)
- 空间复杂度O(1)
2020/10/9 :环形链表
问题 简单
给定一个链表,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
如果链表中存在环,则返回 true 。 否则,返回 false 。
进阶:
你能用 O(1)(即,常量)内存解决此问题吗?
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
提示:
链表中节点的数目范围是 [0, 104]
-105 <= Node.val <= 105
pos 为 -1 或者链表中的一个 有效索引 。
哈希表法
记录下每个地址,查看当前指针是否重合
莫得代码,下面这个方法不香吗!
快慢指针法
两个指针,一个跑得快,一个跑得慢,总有一天会遇到,除非没有环,遇到尽头便结束。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode *ptr1=head,*ptr2=head;
while(ptr1!=NULL && ptr1->next!=NULL){
ptr1=ptr1->next->next;
ptr2=ptr2->next;
if(ptr1==ptr2)
return true;
}
return false;
}
};
- 时间复杂度O(n)
- 空间复杂度O(1)
快慢指针官方解法
class Solution {
public:
bool hasCycle(ListNode* head) {
if (head == nullptr || head->next == nullptr) {
return false;
}
ListNode* slow = head;
ListNode* fast = head->next;
while (slow != fast) {
if (fast == nullptr || fast->next == nullptr) {
return false;
}
slow = slow->next;
fast = fast->next->next;
}
return true;
}
};
- 时间复杂度O(n)
- 空间复杂度O(1)
2020/10/12 : 二叉搜索树的最小绝对差
问题 简单
给你一棵所有节点为非负值的二叉搜索树,请你计算树中任意两节点的差的绝对值的最小值。
示例:
输入:
1
3
/
2
输出:
1
解释:
最小绝对差为 1,其中 2 和 1 的差的绝对值为 1(或者 2 和 3)。
提示:
树中至少有 2 个节点。
本题与 783 https://leetcode-cn.com/problems/minimum-distance-between-bst-nodes/ 相同
中序遍历
根据二叉搜索树的递增顺序。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
void dfs(TreeNode* root,int& min,int& pre){
if(root==nullptr)
return;
dfs(root->left,min,pre);
if(pre==-1)
pre = root->val;
else{
min=min<(root->val-pre)?min:(root->val-pre);
pre = root->val;
}
dfs(root->right,min,pre);
}
int getMinimumDifference(TreeNode* root) {
int min=INT_MAX,pre=-1;
dfs(root,min,pre);
return min;
}
};
- 时间复杂度O(n)
- 空间复杂度O(n)
2020/10/13 : 两两交换链表中的节点
问题 中等
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例:
给定 1->2->3->4, 你应该返回 2->1->4->3.
迭代
/**
* 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* swapPairs(ListNode* head) {
ListNode root(0,head);
ListNode* cur=&root,*tmp=cur->next;
while(cur->next!=nullptr && cur->next->next!=nullptr){
cur->next = tmp->next;
tmp->next = cur->next->next;
cur->next->next = tmp;
cur = tmp;
tmp = tmp->next;
}
return root.next;
}
};
- 时间复杂度O(n)
- 空间复杂度O(1)
2020/10/14 : 查找常用字符
问题 简单
给定仅有小写字母组成的字符串数组 A,返回列表中的每个字符串中都显示的全部字符(包括重复字符)组成的列表。例如,如果一个字符在每个字符串中出现 3 次,但不是 4 次,则需要在最终答案中包含该字符 3 次。
你可以按任意顺序返回答案。
示例 1:
输入:[“bella”,“label”,“roller”]
输出:[“e”,“l”,“l”]
示例 2:
输入:[“cool”,“lock”,“cook”]
输出:[“c”,“o”]
提示:
1 <= A.length <= 100
1 <= A[i].length <= 100
A[i][j] 是小写字母
计数
class Solution {
public:
vector<string> commonChars(vector<string>& A) {
vector<int> minfreq(26, INT_MAX);
vector<int> freq(26);
for (const string& word: A) {
fill(freq.begin(), freq.end(), 0);
for (char ch: word) {
++freq[ch - 'a'];
}
for (int i = 0; i < 26; ++i) {
minfreq[i] = min(minfreq[i], freq[i]);
}
}
vector<string> ans;
for (int i = 0; i < 26; ++i) {
for (int j = 0; j < minfreq[i]; ++j) {
ans.emplace_back(1, i + 'a');
}
}
return ans;
}
};
- 时间复杂度O(n(m+∣Σ∣)), ∣Σ∣为字符集的长度,m 是字符串的平均长度,n 是数组 A 的长度
- 空间复杂度O(∣Σ∣)
2020/10/16 : 有序数组的平方
问题 简单
给定一个按非递减顺序排序的整数数组 A,返回每个数字的平方组成的新数组,要求也按非递减顺序排序。
示例 1:
输入:[-4,-1,0,3,10]
输出:[0,1,9,16,100]
示例 2:
输入:[-7,-3,2,3,11]
输出:[4,9,9,49,121]
提示:
1 <= A.length <= 10000
-10000 <= A[i] <= 10000
A 已按非递减顺序排序。
sort函数法
class Solution {
public:
vector<int> sortedSquares(vector<int>& A) {
vector<int> ans;
for(auto i:A)
ans.push_back(i*i);
sort(ans.begin(),ans.end());
return ans;
}
};
-
时间复杂度:O(nlogn),其中 n是数组 A 的长度。
-
空间复杂度:O(logn)。除了存储答案的数组以外,我们需要 O(logn) 的栈空间进行排序
双指针
输入的数组是非递减序列,因此可以找到一个中间点,是的两边的平方后的树分别递减,递增,再用归并法排序
class Solution {
public:
vector<int> sortedSquares(vector<int>& A) {
vector<int> ans;
int i=0;
while(i<A.size() && A[i]<0)
i++;
int i1=i-1,i2=i;
while(i1>=0 && i2<A.size()){
if(A[i1]*A[i1]>A[i2]*A[i2]){
ans.push_back(A[i2]*A[i2]);
i2++;
}
else{
ans.push_back(A[i1]*A[i1]);
i1--;
}
}
while(i1>=0){
ans.push_back(A[i1]*A[i1]);
i1--;
}
while( i2<A.size()){
ans.push_back(A[i2]*A[i2]);
i2++;
}
return ans;
}
};
- 时间复杂度O(n) 遍历整个数组
- 空间复杂度O(1)
双指针2
将指针分别移动到0和n-1的位置,开始比较,这样就无需上面那么复杂了,更简单
class Solution {
public:
vector<int> sortedSquares(vector<int>& A) {
int n = A.size();
vector<int> ans(n);
for (int i = 0, j = n - 1, pos = n - 1; i <= j;) {
if (A[i] * A[i] > A[j] * A[j]) {
ans[pos] = A[i] * A[i];
++i;
}
else {
ans[pos] = A[j] * A[j];
--j;
}
--pos;
}
return ans;
}
};
- 时间复杂度O(n) 遍历整个数组
- 空间复杂度O(1)
2020/10/18:删除链表的倒数第N个节点
问题 中等
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 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) {
ListNode* fir=head,*sec=head;
for(int i=0;i<n;i++)
fir = fir->next;
if(fir==nullptr)
return head->next;
while(fir->next!=nullptr){
fir = fir->next;
sec = sec->next;
}
fir = sec->next;
sec->next = fir->next;
delete fir;
return head;
}
};
2020/10/19:比较含退格的字符串
问题 简单
给定 S 和 T 两个字符串,当它们分别被输入到空白的文本编辑器后,判断二者是否相等,并返回结果。 # 代表退格字符。
注意:如果对空文本输入退格字符,文本继续为空。
示例 1:
输入:S = “ab#c”, T = “ad#c”
输出:true
解释:S 和 T 都会变成 “ac”。
示例 2:
输入:S = “ab##”, T = “c#d#”
输出:true
解释:S 和 T 都会变成 “”。
示例 3:
输入:S = “a##c”, T = “#a#c”
输出:true
解释:S 和 T 都会变成 “c”。
示例 4:
输入:S = “a#c”, T = “b”
输出:false
解释:S 会变成 “c”,但 T 仍然是 “b”。
提示:
1 <= S.length <= 200
1 <= T.length <= 200
S 和 T 只含有小写字母以及字符 ‘#’。
栈
class Solution {
public:
bool backspaceCompare(string S, string T) {
stack<char> S_s,T_s;
int i=0,j=0;
for(auto c:S){
if(c=='#'){
if(!S_s.empty())
S_s.pop();
}
else{
S_s.push(c);
cout<<c;
}
}
for(auto c:T){
if(c=='#'){
if(!T_s.empty())
T_s.pop();
}
else{
T_s.push(c);
cout<<c;
}
}
return S_s==T_s?true:false;
}
};
- 时间复杂度 O ( m + n ) O(m+n) O(m+n)
- 空间复杂度 O ( m + n ) O(m+n) O(m+n)
2020/10/20:重排链表
问题 中等
给定一个单链表 L:L0→L1→…→Ln-1→Ln ,
将其重新排列后变为: L0→Ln→L1→Ln-1→L2→Ln-2→…
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例 1:
给定链表 1->2->3->4, 重新排列为 1->4->2->3.
示例 2:
给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3.
。。
/**
* 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:
void reorderList(ListNode* head) {
vector<ListNode*> pos;
ListNode* cur=head,*root=head;
while(cur!=nullptr){
pos.push_back(cur);
cur = cur->next;
}
int i1=0,i2=pos.size()-1;
cur = head;
while(i1 < i2){
cur->next = pos[i2--];
if(i2==i1)
cur->next->next = nullptr;
else
cur->next->next = pos[++i1];
cur = cur->next->next;
}
if(cur!=nullptr)
cur->next=nullptr;
}
};
-
时间复杂度 O ( n ) O(n) O(n)
-
空间复杂度 O ( 1 ) O(1) O(1)
2020/10/21:长按键入
问题 简单
你的朋友正在使用键盘输入他的名字 name。偶尔,在键入字符 c 时,按键可能会被长按,而字符可能被输入 1 次或多次。
你将会检查键盘输入的字符 typed。如果它对应的可能是你的朋友的名字(其中一些字符可能被长按),那么就返回 True。
示例 1:
输入:name = “alex”, typed = “aaleex”
输出:true
解释:‘alex’ 中的 ‘a’ 和 ‘e’ 被长按。
示例 2:
输入:name = “saeed”, typed = “ssaaedd”
输出:false
解释:‘e’ 一定需要被键入两次,但在 typed 的输出中不是这样。
示例 3:
输入:name = “leelee”, typed = “lleeelee”
输出:true
示例 4:
输入:name = “laiden”, typed = “laiden”
输出:true
解释:长按名字中的字符并不是必要的。
提示:
name.length <= 1000
typed.length <= 1000
name 和 typed 的字符都是小写字母。
// class Solution {
// public:
// bool isLongPressedName(string name, string typed) {
// char last=' ';
// int i=0,j=0;
// while(j<typed.size()){
// if(i>name.size())
// return false;
// if(name[i]==typed[j]){
// i++;
// j++;
// }
// else{
// if(typed[j]==last)
// j++;
// else
// return false;
// }
// last = typed[j-1];
// }
// if(i<name.size())
// return false;
// while(j<typed.size()){
// if(typed[j]!=last)
// return false;
// j++;
// }
// return true;
// }
// };
class Solution {
public:
bool isLongPressedName(string name, string typed) {
int i = 0, j = 0;
while (j < typed.length()) {
if (i < name.length() && name[i] == typed[j]) {
i++;
j++;
} else if (j > 0 && typed[j] == typed[j - 1]) {
j++;
} else {
return false;
}
}
return i == name.length();
}
};
- 时间复杂度 O ( N + M ) O(N+M) O(N+M)
- 空间复杂度 O ( 1 ) O(1) O(1)
2020/10/22:划分字母区间
问题 中等
字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一个字母只会出现在其中的一个片段。返回一个表示每个字符串片段的长度的列表。
示例 1:
输入:S = “ababcbacadefegdehijhklij”
输出:[9,7,8]
解释:
划分结果为 “ababcbaca”, “defegde”, “hijhklij”。
每个字母最多出现在一个片段中。
像 “ababcbacadefegde”, “hijhklij” 的划分是错误的,因为划分的片段数较少。
提示:
S的长度在[1, 500]之间。
S只包含小写字母 ‘a’ 到 ‘z’ 。
贪心算法+双指针
class Solution {
public:
vector<int> partitionLabels(string S) {
int last[26];
int length = S.size();
for (int i = 0; i < length; i++) {
last[S[i] - 'a'] = i;
}
vector<int> partition;
int start = 0, end = 0;
for (int i = 0; i < length; i++) {
end = max(end, last[S[i] - 'a']);
if (i == end) {
partition.push_back(end - start + 1);
start = end + 1;
}
}
return partition;
}
};
- 时间复杂度O(n) 字符串长度
- 空间复杂度O(∣Σ∣) 字符集个数
2020/10/26 : 有多少小于当前数字的数字
问题 简单
给你一个数组 nums,对于其中每个元素 nums[i],请你统计数组中比它小的所有数字的数目。
换而言之,对于每个 nums[i] 你必须计算出有效的 j 的数量,其中 j 满足 j != i 且 nums[j] < nums[i] 。
以数组形式返回答案。
示例 1:
输入:nums = [8,1,2,2,3]
输出:[4,0,1,1,3]
解释:
对于 nums[0]=8 存在四个比它小的数字:(1,2,2 和 3)。
对于 nums[1]=1 不存在比它小的数字。
对于 nums[2]=2 存在一个比它小的数字:(1)。
对于 nums[3]=2 存在一个比它小的数字:(1)。
对于 nums[4]=3 存在三个比它小的数字:(1,2 和 2)。
示例 2:
输入:nums = [6,5,4,8]
输出:[2,1,0,3]
示例 3:
输入:nums = [7,7,7,7]
输出:[0,0,0,0]
提示:
2 <= nums.length <= 500
0 <= nums[i] <= 100
通过次数63,770提交次数77,238
暴力法
class Solution {
public:
vector<int> smallerNumbersThanCurrent(vector<int>& nums) {
vector<int> ans;
for(int i=0;i<nums.size();i++){
int num=0;
for(int j=0;j<nums.size();j++){
if(nums[i]>nums[j])
num++;
}
ans.push_back(num);
}
return ans;
}
};
- 时间复杂度O(n*n)
- 空间复杂度O(1)
计数排序
class Solution {
public:
vector<int> smallerNumbersThanCurrent(vector<int>& nums) {
vector<int> cnt(101, 0);
int n = nums.size();
for (int i = 0; i < n; i++) {
cnt[nums[i]]++;
}
for (int i = 1; i <= 100; i++) {
cnt[i] += cnt[i - 1];
}
vector<int> ret;
for (int i = 0; i < n; i++) {
ret.push_back(nums[i] == 0 ? 0: cnt[nums[i]-1]);
}
return ret;
}
};
时间复杂度: O ( N + K ) O(N + K) O(N+K),其中 K K K 为值域大小。需要遍历两次原数组,同时遍历一次频次数组 c n t cnt cnt 找出前缀和。
空间复杂度: O ( K ) O(K) O(K)。因为要额外开辟一个值域大小的数组。
2020/10/27 : 二叉树的前序遍历
问题 中等
给定一个二叉树,返回它的 前序 遍历。
示例:
输入: [1,null,2,3]
1
2
/
3
输出: [1,2,3]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?
递归
/**
* 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<int> preorderTraversal(TreeNode* root) {
vector<int> ans;
pretravel(root,ans);
return ans;
}
void pretravel(TreeNode* root,vector<int>& ans){
if(root==nullptr)
return;
ans.push_back(root->val);
pretravel(root->left,ans);
pretravel(root->right,ans);
return;
}
};
- 时间复杂度O(n)
- 空间复杂度O(n)
迭代
其实就是将递归的隐式栈变成显式栈。
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> ans;
stack<TreeNode*> s;
if(root==nullptr)
return ans;
s.push(root);
while(!s.empty()){
TreeNode* tmp=s.top();
s.pop();
ans.push_back(tmp->val);
if(tmp->right!=nullptr)
s.push(tmp->right);
if(tmp->left!=nullptr)
s.push(tmp->left);
}
return ans;
}
};
- 时间复杂度O(n)
- 空间复杂度O(n)
Morris 遍历
。。。不想看了、
2020/10/28 : 独一无二的出现次数
问题 简单
给你一个整数数组 arr,请你帮忙统计数组中每个数的出现次数。
如果每个数的出现次数都是独一无二的,就返回 true;否则返回 false。
示例 1:
输入:arr = [1,2,2,1,1,3]
输出:true
解释:在该数组中,1 出现了 3 次,2 出现了 2 次,3 只出现了 1 次。没有两个数的出现次数相同。
示例 2:
输入:arr = [1,2]
输出:false
示例 3:
输入:arr = [-3,0,1,-3,1,1,1,-3,10,0]
输出:true
提示:
1 <= arr.length <= 1000
-1000 <= arr[i] <= 1000
哈希表
先用一个哈希表计数,在构建一个新的哈希表看有没有相同数的值;
class Solution {
public:
bool uniqueOccurrences(vector<int>& arr) {
map<int,int> m;
for(auto i:arr){
if(m.find(i) == m.end())
m[i]=1;
else
m[i]+=1;
}
map<int,int> c;
for(auto k:m){
if(c.find(k.second) == c.end())
c[k.second]=1;
else
return false;
}
return true;
}
};
- 时间复杂度 O ( N ) O(N) O(N)
- 空间复杂度 O ( N ) O(N) O(N)
2020/10/29 : 求根到叶子节点数字之和
问题 中等
给定一个二叉树,它的每个结点都存放一个 0-9 的数字,每条从根到叶子节点的路径都代表一个数字。
例如,从根到叶子节点路径 1->2->3 代表数字 123。
计算从根到叶子节点生成的所有数字之和。
说明: 叶子节点是指没有子节点的节点。
示例 1:
输入: [1,2,3]
1
/
2 3
输出: 25
解释:
从根到叶子节点路径 1->2 代表数字 12.
从根到叶子节点路径 1->3 代表数字 13.
因此,数字总和 = 12 + 13 = 25.
示例 2:
输入: [4,9,0,5,1]
4
/
9 0
/
5 1
输出: 1026
解释:
从根到叶子节点路径 4->9->5 代表数字 495.
从根到叶子节点路径 4->9->1 代表数字 491.
从根到叶子节点路径 4->0 代表数字 40.
因此,数字总和 = 495 + 491 + 40 = 1026.
深度优先遍历
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
stack<int> num;
int ans=0;
int sumNumbers(TreeNode* root) {
if(root==nullptr)
return 0;
dfs(root);
return ans;
}
void dfs(TreeNode* root){
if(num.empty())
num.push(root->val);
else
num.push(num.top()*10+root->val);
if(root->right==nullptr && root->left==nullptr){
ans+=num.top();
}
else{
if(root->right!=nullptr)
dfs(root->right);
if(root->left!=nullptr)
dfs(root->left);
}
num.pop();
return;
}
};
- 时间复杂度 O ( n ) O(n) O(n)
- 空间复杂度 O ( n ) O(n) O(n)
2020/10/30 :岛屿的周长
问题 简单
给定一个包含 0 和 1 的二维网格地图,其中 1 表示陆地 0 表示水域。
网格中的格子水平和垂直方向相连(对角线方向不相连)。整个网格被水完全包围,但其中恰好有一个岛屿(或者说,一个或多个表示陆地的格子相连组成的岛屿)。
岛屿中没有“湖”(“湖” 指水域在岛屿内部且不和岛屿周围的水相连)。格子是边长为 1 的正方形。网格为长方形,且宽度和高度均不超过 100 。计算这个岛屿的周长。
示例 :
输入:
[[0,1,0,0],
[1,1,1,0],
[0,1,0,0],
[1,1,0,0]]
输出: 16
解释: 它的周长是下面图片中的 16 个黄色的边:
我的暴力法
每个为1 的格子周围只要是0即水和边界都是周长的一部分,因此遍历全矩阵,判断每个格子周围的情况,太粗暴,不建议!!
class Solution {
public:
int islandPerimeter(vector<vector<int>>& grid) {
int ans=0;
for(int i=0;i<grid.size();i++){
for(int j=0;j<grid[i].size();j++){
if(grid[i][j]==0)
continue;
if(grid.size()==1 && grid[i].size()==1){
ans+=4;
continue;
}
if(grid.size()==1){
if(j==0){
if(grid[i][j+1]==0)
ans++;
ans++;
ans++;
ans++;
continue;
}
if(j==grid[i].size()-1){
if(grid[i][j-1]==0)
ans++;
ans++;
ans++;
ans++;
continue;
}
if(j>0 && j<grid[i].size()-1){
if(grid[i][j+1]==0)
ans++;
if(grid[i][j-1]==0)
ans++;
ans++;
ans++;
continue;
}
}
if(grid[i].size()==1){
if(i==0){
if(grid[i+1][j]==0)
ans++;
ans++;
ans++;
ans++;
continue;
}
if(i==grid.size()-1){
if(grid[i-1][j]==0)
ans++;
ans++;
ans++;
ans++;
continue;
}
if(i>0 && i<grid.size()-1){
if(grid[i+1][j]==0)
ans++;
if(grid[i-1][j]==0)
ans++;
ans++;
ans++;
continue;
}
}
if(i>0 && i<grid.size()-1 && j>0 && j<grid[i].size()-1){
if(grid[i][j+1]==0)
ans++;
if(grid[i+1][j]==0)
ans++;
if(grid[i-1][j]==0)
ans++;
if(grid[i][j-1]==0)
ans++;
}
if(i==0 && j==0 ){
if(grid[i][j+1]==0)
ans++;
if(grid[i+1][j]==0)
ans++;
ans++;
ans++;
}
if(i==grid.size()-1 && j==0){
if(grid[i][j+1]==0)
ans++;
if(grid[i-1][j]==0)
ans++;
ans++;
ans++;
}
if(i==grid.size()-1 && j==grid[i].size()-1){
if(grid[i][j-1]==0)
ans++;
if(grid[i-1][j]==0)
ans++;
ans++;
ans++;
}
if(i==0 && j==grid[i].size()-1){
if(grid[i][j-1]==0)
ans++;
if(grid[i+1][j]==0)
ans++;
ans++;
ans++;
}
if(i==0 && j>0 && j<grid[i].size()-1){
if(grid[i][j+1]==0)
ans++;
if(grid[i+1][j]==0)
ans++;
if(grid[i][j-1]==0)
ans++;
ans++;
}
if(i==grid.size()-1 && j>0 && j<grid[i].size()-1){
if(grid[i][j+1]==0)
ans++;
if(grid[i-1][j]==0)
ans++;
if(grid[i][j-1]==0)
ans++;
ans++;
}
if(i>0 && i<grid.size()-1 &&j==grid[i].size()-1){
if(grid[i+1][j]==0)
ans++;
if(grid[i-1][j]==0)
ans++;
if(grid[i][j-1]==0)
ans++;
ans++;
}
if(i>0 && i<grid.size()-1 && j==0){
if(grid[i][j+1]==0)
ans++;
if(grid[i+1][j]==0)
ans++;
if(grid[i-1][j]==0)
ans++;
ans++;
}
}
}
return ans;
}
};
同样的方法的官方代码
class Solution {
constexpr static int dx[4] = {0, 1, 0, -1};
constexpr static int dy[4] = {1, 0, -1, 0};
public:
int islandPerimeter(vector<vector<int>> &grid) {
int n = grid.size(), m = grid[0].size();
int ans = 0;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (grid[i][j]) {
int cnt = 0;
for (int k = 0; k < 4; ++k) {
int tx = i + dx[k];
int ty = j + dy[k];
if (tx < 0 || tx >= n || ty < 0 || ty >= m || !grid[tx][ty]) {
cnt += 1;
}
}
ans += cnt;
}
}
}
return ans;
}
};
//写的这么简单。。。
- 时间复杂度 O ( n ∗ m ) O(n*m) O(n∗m) ,矩阵的长宽。
- 空间复杂度 O ( 1 ) O(1) O(1)