【leetcode每日一题】2020/10月

leetcode10月每日一题

文章目录

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 个黄色的边:

img

我的暴力法

每个为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(nm) ,矩阵的长宽。
  • 空间复杂度 O ( 1 ) O(1) O(1)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值