LeetCode周赛题,日常刷题笔记。

十月第二周(完成三道)

第一道完成的位于上一个文件中。

  1. 1486. XOR Operation in an Array

$O(n)$ 的时间复杂度,如果考察异或操作,那么多和二进制有关。因为数据范围是$10^3$,所以直接暴力求解就ok了。

(也可以归结为模拟题)

python解法

1
2
3
4
5
6
7
class Solution:
    def xorOperation(self, n: int, start: int) -> int:
        res =0
        for i in range(n):
            t = start + 2*i
            res =res ^ (t)
        return res

c++ 解法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class Solution {
public:
    int xorOperation(int n, int start) {
        int res =0;
        for(int i =0; i< n; i++)
        {
            int t =i *2 + start;
            res = res^ t;   
        }
        return res;
        
    }
};
  1. 1487. Making File Names Unique

数据范围 $5*10^4$,这意味着需要是$O(n)$ 的做法。使用dictionary

题解:

For while 是非常常见的结构,for 是有序循环,while 是条件循环。

暴力求解(c++)

 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:
    vector<string> getFolderNames(vector<string>& names) {
        unordered_set<string> dict;
        vector<string> res;
        
        for(auto name: names)
        {
            int i =0;
            string suf;
            
            while(dict.count(name+suf))
            {
                i ++;
                suf ='('+to_string(i) +')';
            }
            dict.insert(name+suf);
            res.push_back(name+suf);
        }
        return res;
    }
};

时间复杂度分析:$N \times 5\times 10^4$ ,$N$ 是很大的常数,所以可能 time out。

优化的点: 对于同一个文件名,如果之前已经查找过,那么不必从头开始查找。

 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
class Solution {
public:
    vector<string> getFolderNames(vector<string>& names) {
        unordered_set<string> dict;
        unordered_map<string, int> cnt;
        vector<string> res;
        
        for(auto name: names)
        {
            int i =0;
            string suf;
            if (cnt[name] ) i =cnt[name];
            # 这里能够减少时间复杂度
            while(dict.count(name+suf))
            {
                i ++;
                suf ='('+to_string(i) +')';
            }
            cnt[name] =i;
            dict.insert(name+suf);
            res.push_back(name+suf);
        }
        return res;
    }
};

python 版本的code (不仅是算法思路,还需要算法的实现)

下面的解法是正确的,但是 time out (暴力解法)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class Solution:
    def getFolderNames(self, names: List[str]) -> List[str]:
        from collections import Counter
        dic =Counter()
        dic_ =Counter()
        
        res =[]
        
        for name in names:
            i = 0
            suf =""
            # 这里的 dic 更像是一种 set() 判别是否存在,而非真正dictionary 的功能
            # 每次i 的变化都是从0开始 +1,实际上可以使用dic 保存一个最大值
            while dic.get(name+suf, 0):
                i +=1
                suf ="({})".format(i)
            dic[name+suf] =1
            res.append(name+suf)
        return res

经过上述思路优化的做法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution:
    def getFolderNames(self, names: List[str]) -> List[str]:
        from collections import Counter
        dic =Counter()
        dic_ =Counter()
        
        res =[]
        
        for name in names:
            i = 0
            suf =""
            # 这里的 dic 更像是一种 set() 判别是否存在,而非真正dictionary 的功能
            # 每次i 的变化都是从0开始 +1,实际上可以使用dic 保存一个最大值
            if dic_.get(name, 0):i =dic_.get(name)
              
            while dic.get(name+suf, 0):
                i +=1
                suf ="({})".format(i)
            dic[name+suf] =1
            dic_[name] =i
            res.append(name+suf)
        return res

将暴力解法写出来,然后去优化,也是一种很基本的解题思路。

十月第三周(完成两道)

1475. Final Prices With a Special Discount in a Shop

时间复杂度是$O(n^2)$

c++ 解法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
    // 能想到的算法是 $O(n^2)$,
   //   n =500,所以暴力求解不是最优的,但是能过的 
    vector<int> finalPrices(vector<int>& prices) {
        int n =prices.size();
        vector<int> res(n, 0);
        int j ;
        for(int i =0; i<n-1;i ++ )
        {
            j =i +1;
            while(j <n && prices[j] > prices[i])
                j ++;
            if (j !=n) res[i] =prices[i] -prices[j];
            else
                res[i] =prices[i];
        }
        res[n-1] =prices[n-1];
        return res;
    }
};

python解法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class Solution:
    def finalPrices(self, prices: List[int]) -> List[int]:
        # 暴力求解一波
        res =[]
        n =len(prices)
        for i in range(0, n-1): 
            j =i +1
            while j < n and prices[j] > prices[i]:
                j +=1
            if j !=n: 
                res.append(prices[i] -prices[j])
            else:
                res.append(prices[i])
        res.append(prices[-1])
        return res

优化时间复杂度

寻找最近一个比他小的数字,使用单调栈的思想。

c++ 实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
    // 寻找距离最近的比当前数小的数字
    vector<int> finalPrices(vector<int>& prices) {
        
        stack<int> stk;
        vector<int> res;
        int n =prices.size();
        for(int i =n-1; i>=0; i--)
        {
            int t =prices[i];
            while(stk.size() && t < stk.top()) stk.pop();
            if(stk.size() && stk.top() <= t) res.push_back(t -stk.top());
            else
                res.push_back(t);
            while(stk.size() && t ==stk.top()) stk.pop();
            stk.push(t);
        }
        return vector<int>{res.rbegin(), res.rend()};
    }
};

python 实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class Solution:
    # 距离最近的小数,单调栈思想,最后的时间复杂度是$O(n)$
    def finalPrices(self, prices: List[int]) -> List[int]:
        res =[]
        stk =[]
        n =len(prices)
        for i in range(n-1, -1, -1):
            t =prices[i]
            while stk and stk[-1] > t:
                stk.pop()
            if stk and stk[-1] <= t:
                res.append(t-stk[-1])
            else:
                res.append(t)

            stk.append(t)
        return res[::-1]

1476. Subrectangle Queries

因为数据范围是 $n=100$,那么使用暴力求解就能解决问题。

思路一

python实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class SubrectangleQueries:

    def __init__(self, rectangle: List[List[int]]):
        self.query =rectangle
        
    def updateSubrectangle(self, row1: int, col1: int, row2: int, col2: int, newValue: int) -> None:
        for  i in range(row1, row2+1):
            for j in range(col1, col2+1):
                self.query[i][j] =newValue

    def getValue(self, row: int, col: int) -> int:
        return self.query[row][col]


# Your SubrectangleQueries object will be instantiated and called as such:
# obj = SubrectangleQueries(rectangle)
# obj.updateSubrectangle(row1,col1,row2,col2,newValue)
# param_2 = obj.getValue(row,col)

c++ 实现

多注意一下c++ 中双重数组的声明和初始化。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class SubrectangleQueries {
public:
    vector<vector<int>> rect;
    SubrectangleQueries(vector<vector<int>>& rectangle) {
        rect =rectangle;   
    }
    
    void updateSubrectangle(int row1, int col1, int row2, int col2, int newValue) {
        for(int i =row1; i<= row2; i ++)
            for(int j =col1; j<= col2; j++)
                rect[i][j] =newValue;
    }
    int getValue(int row, int col) {
        return rect[row][col];
    }
};

思路一在 updateSubrectangle 比较耗时。还有一种思路:维护一个更新表,将用户的操作以key-value 的方式保存起来。

python实现代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class SubrectangleQueries:
    # 第二种思路:记录update过程,注意 stk中存储的 [(), ()]修改记录,如果修改记录中没有,那么从原来的rectangle中找找
    # python 中如果不再修改,那么是() 要不 [] 更优化
    def __init__(self, rectangle: List[List[int]]):
        self.update = []
        self.query =rectangle

    def updateSubrectangle(self, row1: int, col1: int, row2: int, col2: int, newValue: int) -> None:
        self.stk.update((row1, col1, row2, col2, newValue))
        
    def getValue(self, row: int, col: int) -> int:
        n =len(self.update)
        
        for i in range(n-1, -1, -1):
            if row >= self.update[i][0] and row <= self.update[i][2] and col >= self.update[i][1] and col<= self.update[i][3]:
                return self.update[i][-1]
        return self.query[row][col]

更加简洁的写法

优化了判断函数。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
class SubrectangleQueries:
    # 第二种思路:记录update过程
    def __init__(self, rectangle: List[List[int]]):
        self.update = []
        self.query =rectangle

    def updateSubrectangle(self, row1: int, col1: int, row2: int, col2: int, newValue: int) -> None:
        self.update.append((row1, col1, row2, col2, newValue))
        

    def getValue(self, row: int, col: int) -> int:
        n =len(self.update)
        
        def inside(x, y, R):
            return R[0] <=x <= R[2] and R[1] <= y<=R[3]
        
        for i in range(len(self.update) -1, -1, -1):
            if inside(row, col, self.update[i][:4]):
                return self.update[i][-1]

        return self.query[row][col]

c++ 实现上述思路

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class SubrectangleQueries {
public:
    vector<vector<int>> query;
    //stack<int> stk; // 需要使用二维列表实现
    vector<vector<int>> update;
    SubrectangleQueries(vector<vector<int>>& rectangle) {
        query =rectangle;
    }
    
    void updateSubrectangle(int row1, int col1, int row2, int col2, int newValue) {
        update.push_back({row1, col1, row2, col2, newValue}); // c++ 中这属于简化之后的构造函数
    }
    
    int getValue(int row, int col) {
        
        for(int i =update.size()-1; i >=0 ; i--)
        {
            if (row >= update[i][0] && row <= update[i][2] && col >= update[i][1] && col<= update[i][3])
                return udpate[i][4];
        }
        return query[row][col];
    }
};

十月第四周(完成一道)

  1. Path Crossing

判断路线是否相交

分析:数据范围是$10^4$,那么应该是$nlogn$的做法(最多是$n^2$) 的做法?属于模拟题?

正确的解法: 使用dictionary 保存走过的点的坐标,如果发现已经走过,那么 return true否则 return false

c++ 解答

注意set.find()set.count() 对应的判断条件。使用set 就可以表示无修改的dictionary。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
    bool isPathCrossing(string path) {
        unordered_set<string> dict;
        dict.insert("00");
        int x=0, y=0;
        for(auto ch: path)
        {
            if (ch=='N') y +=1;
            else if (ch =='E') x +=1;
            else if (ch =='S') y -=1;
            else if (ch =='W') x -=1;
            string t =to_string(x)+to_string(y);
            if (dict.count(t) ) return true;
            //if (dict.find(t)  != dict.end()) return true;
            dict.insert(t);
        }
        return false;
        
    }
};

python 解答

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class Solution:
    def isPathCrossing(self, path: str) -> bool:
        dic =set()
        dic.add("00")
        x, y =0, 0
        for ch in path:
            if ch =='N': y  +=1
            elif ch =='E': x +=1
            elif ch =='S': y -=1
            elif ch =='W': x -=1
            t =str(x)+str(y)
            if t in dic: return True
            dic.add(t)
        return False
    

十一月第一周(完成一道)

1497. Check If Array Pairs Are Divisible by k

解题思路:数学题。数字是否可以被k 整除转换为余数问题。如果余数为0,那么可以被其整除;如果两个数字之和可以被整除,那么余数之和相加为k。

c++ 解法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class Solution {
public:
    bool canArrange(vector<int>& arr, int k) {
        vector<int> r(k, 0);
        for(auto num: arr)
            r[(num%k +k)%k] +=1;
        
        if(r[0] %2 ==1) return false;
        
        for(int i =1; i<k ;i++)
            if(r[i] != r[k-i]) return false;
        return true;
        
    }
};

最后的for 循环还可以优化成双指针的形式。

 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 canArrange(vector<int>& arr, int k) {
        vector<int> r(k, 0);
        for(auto num: arr)
            r[(num%k +k)%k] +=1;
        
        if(r[0] %2 ==1) return false;
        
        for(int i =1, j =k-1; i<j; i++, j --)
            if(i ==j) 
            {
                if(r[i] %2 !=0) return false;
            }
            else
            {
                if(r[i] != r[j] ) return false;
            }
        
        return true;
        
    }
};

python 解法 (按照第二种写法)

1
2
3
4
5
6
7
8
class Solution:
    def canArrange(self, arr: List[int], k: int) -> bool:
        
        r = [0] *k
        for num in arr:
            r[(num%k +k) %k] +=1
        
        return r[0]%2 ==0 and all( r[i] ==r[k-i] for i in range(1,k//2+1))

十一月第二周(完成三道)

1498. Number of Subsequences That Satisfy the Given Sum Condition

主要是思路问题,查看最后给出的例子可以发现,当序列中任一两数之和满足条件,那么是可以使用数学公式的。所以可以先排序,然后使用二分去查找合适的区间。最后的时间复杂度是 $O(nlogn)$。

任意序列(sequence) 和任意区间的区别:前者可以是非连续,后者是连续的。

python 求解

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class Solution:
    def numSubseq(self, nums: List[int], target: int) -> int:
        # 如果是 subarry 可以使用预处理找到每个区间的 最大最小值? 但是这个是 subsequence,没有什么思路
        # n =10^5,算法复杂度一般在nlogn 或者 O(n) ,但还是没有思路
        MOD = 1000000000 +7
        nums.sort()
        res =0
        l, r = 0, len(nums) -1
        while l <= r:
            if nums[l] +nums[r] > target: r -=1
            else:
                res =(res+ pow(2, r-l, MOD) ) % MOD
                l +=1
        return res

python 中的一个函数 pow(x, y, z),其中 x is the base, y is the exponent, z (optional) is used for modulus.

(x**y) % z

c++解法

 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
class Solution {
public:
    int numSubseq(vector<int>& nums, int target) {
        int res =0, n =nums.size();
        vector<int> pow(n,1); // 这个就是一个预处理
        int MOD =1000000000 +7;
        
        for(int i =1; i <n; i++)
            pow[i] =(pow[i-1] *2) %MOD;
        
        int l =0, r =n-1;
        sort(nums.begin(), nums.end());
        
        while (l <= r)
        {
            if ( nums[l] + nums[r] > target) 
                r -=1;
            else
            {
                
                res  =( res + pow[r-l] %MOD )% MOD;
                l +=1;
            }
                
        }
        return res;
    }
};

1491. Average Salary Excluding the Minimum and Maximum Salary

题目很简单,简单的遍历一下就可以

c++ 实现代码

(需要记住的是INT_MAXINT_MIN 两个常量)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class Solution {
public:
    double average(vector<int>& salary) {
        double res =0.0;
        int min_v =INT_MAX, max_v =INT_MIN;
        for(auto num : salary)
        {
            res += num;
            min_v = min(min_v, num);
            max_v =max(max_v, num);
        }
        return (res -min_v -max_v )/(salary.size() -2);
    }
};

python实现代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class Solution:
    def average(self, salary: List[int]) -> float:
        min_v, max_v = float("inf"), -float("inf")
        res =0
        for num in salary:
            res += num
            min_v =min(min_v, num)
            max_v =max(max_v, num)
        return (res -min_v -max_v)*1.0/(len(salary) -2)
    

1492. The kth Factor of n

数据量是 1000,那么使用暴力枚举就可以: 先找出所有的除数,然后得到。时间复杂度是$O(n)$。

python 解法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class Solution:
    def kthFactor(self, n: int, k: int) -> int:
        res=[]
        for i in range(1, n+1):
            if n%i ==0:
                res.append(i)
        if k <= len(res):
            return res[k-1];
        else:
            return -1

c++ 解法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class Solution {
public:
    int kthFactor(int n, int k) {
        vector<int> res;
        for(int i =1; i<=n; i++)
        {
            if( n%i ==0) res.push_back(i);
        }
        if (res.size() >=k)
            return res[k-1];
        else
            return -1;   
    }
};

上述解法并没有利用到左右两个数字是“对称”的信息。所以可以从枚举每个数字到枚举每个整除数。优化一下时间复杂度 $O(\sqrt(n))$。

c++ 解法

 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
class Solution {
public:
    int kthFactor(int n, int k) {
        vector<int> beg, end;
        
        int i =1;
        while (i *i <=n)
        {
            if (n%i ==0)
            {
                beg.push_back(i);
                if (i *i !=n)
                    end.push_back(n/i);
            }
                
            i +=1;
        }
        if (k <= beg.size())
            return beg[k-1];
        else if ( k<= beg.size() +end.size())
            return end[end.size() +beg.size() -k];
        return -1;
        
    }
};

python 解法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class Solution:
    # 数据量是 1000,那么使用暴力枚举就可以
    # 先找出所有的除数,然后得到
    def kthFactor(self, n: int, k: int) -> int:
        beg, end =[], []
        i =1
        while i *i <= n:
            if n%i ==0:
                beg.append(i)
                if i *i != n:
                    end.append(n//i)
            i +=1
            
        if k <= len(beg):
            return beg[k-1]
        elif k <= len(beg) +len(end):
            return end[len(beg) +len(end) -k]
        return -1

十一月第三周(完成一道)

1503. Last Moment Before All Ants Fall Out of a Plank

python 实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Solution:
    # 这个比较难的抽象出来模型,没有什么思路
    # 是模拟题。对于向左走的 ant,所需要的时间是其初始位置;对于向右走的ant,所需要的时间是其当前的位置。然后求解所有可能的最大值
    # 算法时间复杂度是 O(n)
    def getLastMoment(self, n: int, left: List[int], right: List[int]) -> int:
        res = -1
        for item in left:
            res =max(res, item)
        for item in right:
            res =max(res, n -item)
        return res
    

c++ 实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class Solution {
public:
    int getLastMoment(int n, vector<int>& left, vector<int>& right) {
        
        int res =-1;
        for(auto item: left)
            res =max(res, item);
        for(auto item: right)
            res =max(res, n -item);
        return res;
            
    }
};

十一月第四周(完成两道)

1504. Count Submatrices With All Ones

因为数据范围是 150,那么可以使用 $n^3$ 的做法;当然是可以使用单调栈进行优化,然后时间复杂度是 $n^2$。判断是否可以使用单调栈,问题中是否包含这寻找左侧最近的最小元素(左侧意味着已经处理过,遍历过)。

以下是单调栈优化过的。

c++ 实现

 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
38
39
40
41
42
class Solution {
public:
    int numSubmat(vector<vector<int>>& mat) {
        int rows =mat.size(), cols =mat[0].size();
        // 二维vector 的书写
        vector<vector<int>> f(rows, vector<int>(cols));
        
        for(int i =0; i< rows; i++)
            for(int j =0; j< cols; j++)
                if(mat[i][j])
                {
                    f[i][j] =1;
                    if(i) f[i][j] += f[i-1][j];
                }
                else
                    f[i][j] =0;
        
        int res =0;
        for(int i =0; i < rows; i++)
        {
            stack<pair<int, int>> stk;
            for(int j =0; j< cols; j++)
            {
                int s =0;
                
                while(stk.size() && f[i][stk.top().first] >= f[i][j]) stk.pop();
                
                if(stk.size())
                {
                    s += stk.top().second;
                    s += f[i][j] *(j - stk.top().first);
                }
                else
                    s += f[i][j] *(j+1);
                stk.push({j, s});
                res += s;
                    
            }
        }
        return res;
    }
};

python 实现

 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
class Solution:
    def numSubmat(self, mat: List[List[int]]) -> int:
        
        res =0
        rows, cols =len(mat), len(mat[0])
        f = [ [0] * cols for _ in range(rows)]
    
        for i in range(rows):
            for j in range(cols):
                if mat[i][j]:
                    f[i][j] =1
                    if i : f[i][j] += f[i-1][j]
        
        for i in range(rows):        
            stk =[]
            for j in range(cols):
                s =0
                
                while stk and f[i][stk[-1][0]] >= f[i][j]: stk.pop()
        
                if stk:
                    s += stk[-1][1] # 累加之前的结果
                    s += (j- stk[-1][0]) * f[i][j]
                else:
                    s += (j+1) *f[i][j]
                stk.append([j, s])
                res +=s
        return res

可以写得更加紧凑

 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
class Solution:
    def numSubmat(self, mat: List[List[int]]) -> int:
        
        res =0
        rows, cols =len(mat), len(mat[0])
        f = [ [0] * cols for _ in range(rows)]

        for i in range(rows):        
            stk =[]
            for j in range(cols):
                if mat[i][j]:
                    f[i][j] =1
                    if i : f[i][j] += f[i-1][j]
                s =0
                
                while stk and f[i][stk[-1][0]] >= f[i][j]: stk.pop()
        
                if stk:
                    s += stk[-1][1] # 累加之前的结果
                    s += (j- stk[-1][0]) * f[i][j]
                else:
                    s += (j+1) *f[i][j]
                stk.append([j, s])
                res +=s
        return res
        

1507. Reformat Date

python 比较擅长字符串处理,下面的解法的缺点是使用了int() 转换函数;优点 是使用$ a<= char <= z$ 进行字符的判断和处理。

python解法

(下面是使用了一种更加优化的方法,没有调用python 自带的int 函数)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Solution:
    def reformatDate(self, date: str) -> str:
        mon_dic={"Jan":"01", 
                "Feb": "02", 
                "Mar": "03",
                "Apr":"04", 
                "May" :"05",
                "Jun": "06",
                "Jul" : "07", 
                "Aug" :"08", 
                "Sep" : "09", 
                "Oct" :"10", 
                "Nov" : "11", 
                "Dec" :"12"}
        # 因为字符串是符合某种规范,所以按照长度分为两类
        if len(date) ==13:
            return date[-4:] + '-' + mon_dic[date[-8:-5]] + '-' + date[:2]
        else:
            return date[-4:] + '-' +mon_dic[date[-8:-5]] + '-0'+date[0]

c++ 实现的时候,多使用substr() 函数。

 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:
    // c++ 中处理字符串: 合理使用substr 
    string reformatDate(string date) {
        unordered_map<string, string> mp;
        
        mp["Jan"] ="01";
        mp["Feb"] ="02";
        mp["Mar"] ="03";
        mp["Apr"] ="04";
        mp["May"] ="05" ;
        mp["Jun"] ="06";
        mp["Jul"] ="07";
        mp["Aug"] ="08";
        mp["Sep"] ="09";
        mp["Oct"] ="10";
        mp["Nov"] ="11";
        mp["Dec"] ="12";
        
        string day;
        int offset ;
        if(isdigit(date[1]))
        {
            day = date.substr(0, 2);
            offset =1;
        }
        else
        {
            day = '0' +date.substr(0, 1);
            offset =0;
        }
        string month =mp[date.substr(offset+4, 3)];
        string year = date.substr(8+offset);
        return year+"-" +month +"-" +day;
    }
};

十二月第一周(完成两道)

  1. 1508. Range Sum of Sorted Subarray Sums

python 实现(这种方式会timeout),尽管分析是可以在 $O(n^2)$ 完成,但实际上不行。

 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:
    # 暴力求解:1. 得到 subarry sum (n^2) 2. sort() nlogn  3. 选择 [left, right],是O(n) 算法。 N =10^3 ,所以是可以满足条件的。
    def sum_with_modu(self, arr: List[int], MOD :int) -> int:
        res =0
        for item in arr:
            res += (item %MOD)
        return res
    def rangeSum(self, nums: List[int], n: int, left: int, right: int) -> int:
        MOD =1000000000 +7
        sub_sum =[]
        n =len(nums)
        for i in range(n+1):
            for j in range(i+1, n+1):
                tmp =nums[i:j]
                sub_sum.append(self.sum_with_modu(tmp, MOD))
        
        sub_sum.sort()
        #print(sub_sum)
        res =0
        for i in range(left-1, right):
            res += (sub_sum[i] %MOD)
        return res
        

不要使用内置的 sum() 去计算,使用以下的代码是可以通过的。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class Solution:
    def rangeSum(self, nums: List[int], n: int, left: int, right: int) -> int:
        
        MOD =1000000000 +7
        sums =[]
        n =len(nums)
        for i in range(n):
            s =0
            for j in range(i, n):
                s += nums[j]
                sums.append(s)
        sums.sort()
        #print(sums)
        ans =0
        for i in range(left-1, right):
            ans += sums[i]
        return ans %MOD;

c++ 实现

 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
class Solution {
public:
    int rangeSum(vector<int>& nums, int n, int left, int right) {
        const int mode =1000000007;
        vector<int> sums;
        
        for(int i =0; i< n; i ++)
        {
            int t =0;
            for(int j =i ; j< n; j++)
            {
                t += nums[j];
                sums.push_back(t);
            }
        }
        
        sort(sums.begin(), sums.end());
        long long res =0;
        for(int i =left -1 ; i <= right -1; i ++)
        {
            res += sums[i];
        }
        return res %mode;
    }
};

1509. Minimum Difference Between Largest and Smallest Value in Three Moves

其实可以在线性时间内解决,分别找出一个list 中最大的三个数字和最小的三个数字,但实现起来很复杂。

c++ 实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class Solution {
public:
    // 时间复杂度 nlogn,使用排序。求解最大数和最小数之间的最小差值。一般来说可以按照贪心的思路求解,修改最大或者最小的三个数字。
    // 那么有四种组合:修改最大的三个数字,修改最大两个和最小的一个,修改最大一个 和最小两个,修改最小三个,然后比较四种方案的最小值
    int minDifference(vector<int>& nums) {
        if (nums.size() <=4 ) return 0;
        int n =nums.size();
        sort(nums.begin(), nums.end());
        return min( min(nums[n-4] -nums[0], nums[n-3] -nums[1]), min(nums[n-2] -nums[2], nums[n-1] -nums[3]));
    }
};

python 实现(可以简化min 函数的书写)

1
2
3
4
5
6
class Solution:
    def minDifference(self, nums: List[int]) -> int:
        if len(nums) <= 4: return 0
        n =len(nums)
        nums.sort()
        return min( nums[n-4] -nums[0],  nums[n-3] -nums[1], nums[n-2] -nums[2], nums[n-1] -nums[3])

十二月第二周(完成两道)

1510. Stone Game IV

LeetCode 最后一题一般都是一个模板题。(所以多积累一些)

经典的博弈论问题。必胜或者必败,不存在平局。

必胜态:能走到某一个必败态;必败态:只能走到必胜态。定义 f[i] 的状态,可能是必胜态也可能是必败态。

c++实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class Solution {
public:
    bool winnerSquareGame(int n) {
        vector<bool> st(n+1);
        st[0] =false;
        
        for(int i =1; i<=n ; i++)
            for(int j=1; j *j <=i; j++)
                if ( st[i -j *j] ==false)
                {
                    st[i] =true;
                    break;
                }
        return st[n];
    }
};

python 实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Solution:
    def winnerSquareGame(self, n: int) -> bool:
        st =[ False] *(n +1)
        for i in range(1,n+1):
            j =1
            while j *j <=i:
                if st[i -j *j] == False:
                    st[i] =True
                    break
                j +=1
        return st[n]
        

1512. Number of Good Pairs

数据范围是 100,那么暴力求解就行。那么便是 $n^2$ 的时间复杂度。

python 解法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class Solution:
    def numIdenticalPairs(self, nums: List[int]) -> int:
        res =0
        n =len(nums)
        for i in range(0, n):
            j =i +1
            while  j < n:  
                if nums[i] ==nums[j]:
                    res +=1
                j +=1 
        return res

优化成 $nlogn$ 时间复杂度 (python 实现)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Solution:
    def numIdenticalPairs(self, nums: List[int]) -> int:
        # 先排序,然后双指针。最后的时间复杂是 nlogn
        nums.sort()
        res =0
        n =len(nums)      
        for i in range(n):
            j =i +1
            while j < n and nums[i] ==nums[j]:
                res +=1
                j += 1
        return res

c++ 实现第二种算法。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class Solution {
public:
    int numIdenticalPairs(vector<int>& nums) {
        int res =0;
        sort(nums.begin(), nums.end());
        for(int i =0; i< nums.size(); i++)
        {
            int j =i +1;
            while (j < nums.size() && nums[i] ==nums[j])
            {
                res +=1;
                j ++;
            }          
        }
        return res;
    }
};

十二月第三周(完成两道)

1513. Number of Substrings With Only 1s

数据量 $O(10^5)$ ,所以可以确定是 $O(n)$ 或者 $nlogn$ 的算法。根据最后一个case 可以知道如果都是1,那么可以使用数学的方式处理,所以就是一个 for-while 循环。空间上可以不必要使用 list 保存。

python解法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Solution:
    def numSub(self, s: str) -> int:
        i =0
        substr =[]
        MOD =1000000007
        while i < len(s):
            if s[i] =='1':
                j =i 
                while j < len(s) and s[j] =='1':
                    j +=1
                substr.append(s[i:j])
                i =j+1
            else:
                i +=1
        res =0
        for sub in substr:
            len_s =len(sub) 
            res +=( (1 +len_s) *len_s //2  %MOD )
        return res

c++ 写法

(在Python中的 substring 也是没有必要的,因为最后参与计算的是 len(substr)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
    // 将string 分割成单个的 substring,这些 substring全部都是1
    int numSub(string s) {
        const int MOD =1000000007;
        int res =0;
        for(int i =0; i< s.size(); i ++)
        {
            if (s[i] =='1')
            {
                int j =i ;
                while (j< s.size() & s[j]=='1') j +=1;
                
                long long n =j -i;
                res +=( (n +1)* n/2 %MOD );
                i =j;
            }
        }
        return res;
    }
};

1518. Water Bottles

模拟题的思路,需要使用到取整和取余两个知识点。

c++ 解法。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class Solution {
public:
    // 这个是模拟题,每次都是取其商,然后余数是累加到下一次的结果中
    int numWaterBottles(int numBottles, int numExchange) {
        int res =0;
        int t1, t2;
        res += numBottles;
        while (numBottles >= numExchange)
        {   
            t1= (numBottles / numExchange);
            t2 = numBottles % numExchange;
            res += t1;
            numBottles =t1 + t2;
            //cout << t1<< " "<< t2<<" " << numBottles<< endl;
        }
        return res;
    }
};

python 解法

(相同的思路,使用python 进行实现)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Solution:
    def numWaterBottles(self, numBottles: int, numExchange: int) -> int:
        
        res =0
        res += numBottles
        
        while numBottles >= numExchange:
            
            res += (numBottles // numExchange)
            numBottles = (numBottles //  numExchange) + (numBottles % numExchange)
        
        return res

十二月第四周(完成一道)

1519. Number of Nodes in the Sub-Tree With the Same Label

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class Solution {
public:
    // 数据范围是 10^5, 所以最好是 O(n) 或者 O(nlogn) 的做法
    //  可以在O(n) 时间内完成,从底部开始层序遍历
    // 可以复习一下 树的遍历(dfs,bfs 和层序遍历)
    // 从上到下的层序遍历 可以使用 stack 实现;但是从下往上的层序遍历不会写 (这道题目并不是按照指针的方式给出了 树,而是给出了边,无向图的思路)
    // 树形dp 问题
    vector<int> countSubTrees(int n, vector<vector<int>>& edges, string labels) {
        
    }
};

视频讲解:https://www.acwing.com/video/1507/

c++ 实现

 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
38
39
40
class Solution {
    
private:
    
    vector<vector<int>> f;
    
    void dfs(int u, int fa, vector<vector<int>> &g)
    {
        for(auto v: g[u])
        {
            if (v!= fa)
            {
                dfs(v, u, g);
                for(int i =0 ; i< 26; i++)
                    f[u][i] += f[v][i];
            }
        }
    }
public:
    // 这个是树形dp 问题
    vector<int> countSubTrees(int n, vector<vector<int>>& edges, string labels) {
        
        vector<vector<int>> g(n);
        for(const auto e: edges)
        {
            int a =e[0], b =e[1];
            g[a].push_back(b), g[b].push_back(a);
        }
        f.resize(n, vector<int>(26, 0));
        // 状态表示需要初始化
        for(int i =0; i< n; i++)
            f[i][labels[i]-'a'] ++;
        
        dfs(0, -1, g);
        vector<int> res(n);
        for(int i =0 ; i< n; i++)
            res[i] += f[i][labels[i] -'a'];
        return res;
    }
};

python 实现, python 中使用嵌套函数(inner function) 是很好用的,直接共享了变量。ord() 小函数。

 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:
    # python 实现的时候有 嵌套函数的概念,所以可以好好利用一下
    def countSubTrees(self, n: int, edges: List[List[int]], labels: str) -> List[int]:
        
        
        g =defaultdict(list)
        
        for e in edges:
            a, b =e[0], e[1]
            g[a].append(b)
            g[b].append(a)
            
        
        # 状态转移的表示
        f =[[0] *26 for _ in range(n)]
        
        for i in range(n):
            f[i][ord(labels[i]) -97] +=1
            
        def dfs(cur, pa):
            for v in g[cur]:
                if v != pa:
                    dfs(v, cur)
                    for i in range(26):
                        f[cur][i] += f[v][i]
        
        dfs(0, -1)
        
        res =[0] *n
        for i in range(n):
            res[i] = f[i][ord(labels[i]) -97]

        return res