LeetCode每日一题 2022年2月

本文介绍了多种使用滑动窗口和贪心策略解决的算法问题,包括寻找最长美好子字符串、反转单词前缀、斐波那契数字数目、正方形矩形计数、黄金矿工问题、唯一元素的和、网格照明、差绝对值为K的数对数目、最简分数、学生分数最小差值、飞地数量、煎饼排序、一比特字符判断、增量元素最大差值以及最多可达成的换楼请求数。通过这些实例展示了滑动窗口和贪心策略在解决复杂问题时的有效性和效率。
摘要由CSDN通过智能技术生成

在这里插入图片描述

2.1 lc.1763 最长的美好子字符串

  • 滑动窗口
class Solution {
public:
    string longestNiceSubstring(string s) {
        int maxPos = 0, maxLen = 0;
        auto check = [&](int typeNum) {
            vector<int> lowerCnt(26);
            vector<int> upperCnt(26);
            int cnt = 0;
            for (int l = 0, r = 0, total = 0; r < s.size(); ++r) {
                int idx = tolower(s[r]) - 'a';
                if (islower(s[r])) {
                    ++lowerCnt[idx];
                    if (lowerCnt[idx] == 1 && upperCnt[idx] > 0) {
                        ++cnt;
                    }
                } else {
                    ++upperCnt[idx];
                    if (upperCnt[idx] == 1 && lowerCnt[idx] > 0) {
                        ++cnt;
                    }
                }
                total += (lowerCnt[idx] + upperCnt[idx]) == 1 ? 1 : 0;

                while (total > typeNum) {
                    idx = tolower(s[l]) - 'a';
                    total -= (lowerCnt[idx] + upperCnt[idx]) == 1 ? 1 : 0;
                    if (islower(s[l])) {
                        --lowerCnt[idx];
                        if (lowerCnt[idx] == 0 && upperCnt[idx] > 0) {
                            --cnt;
                        }
                    } else {
                        --upperCnt[idx];
                        if (upperCnt[idx] == 0 && lowerCnt[idx] > 0) {
                            --cnt;
                        }
                    }
                    ++l;
                }
                if (cnt == typeNum && r - l + 1 > maxLen) {
                    maxPos = l;
                    maxLen = r - l + 1;
                }
            }
        };

        int mask = 0;
        for (char & ch : s) {
            mask |= 1 << (tolower(ch) - 'a');
        }
        int types = __builtin_popcount(mask);
        for (int i = 1; i <= types; ++i) {
            check(i);
        }
        return s.substr(maxPos, maxLen);
    }
};

2.2 lc.2000 反转单词前缀

  • 中间用 if 判断一下
class Solution {
public:
    string reversePrefix(string word, char ch) {
        int l = 0 , r = 0 ;
        while(r < word.size()){
            if(word[r] == ch) break;
            r ++ ;
        }
        if(r == word.size()) return word ;
        while(l < r){
            swap(word[l] , word[r]);
            l ++ ; r -- ;
        }
        return word ;
    }
};

2.3 lc.1414 和为k的最少斐波那契数字数目

  • 贪心小模拟
class Solution {
public:
    int findMinFibonacciNumbers(int k) {       
        int cnt = 0 ;
        while(k > 0){
            int a = 1 , b = 1 ;
            while(b <= k){
                int tmp = b ;
                b = b + a ;
                a = tmp ;
            }
            k = k - a ;
            cnt ++ ;
        }
        return cnt ;
    }
};

2.4 lc.1725 可以形成最大正方形的矩形

  • 贪心小模拟
class Solution {
public:
    int countGoodRectangles(vector<vector<int>>& rectangles) {
        int cnt , maxlen = 0 ;
        for(int i = 0 ; i < rectangles.size() ; i ++){
            int premax = 0 ;
            if(rectangles[i][0] > rectangles[i][1]) premax = rectangles[i][1] ;
            else premax = rectangles[i][0] ;
            if(premax > maxlen) {
                cnt = 1 ;
                maxlen = premax ;
            }
            else if(premax == maxlen) cnt ++ ;
        }
        return cnt ;
    }
};

初四也是 easy 呢。

2.5 lc.1219 黄金矿工

  • DFS
class Solution {
public:
    int ans = 0 ;
    void dfs(int i, int j, int sum, vector<vector<int>>& grid){
        int m = grid.size() , n = grid[0].size() ;
        if(i < 0 || i >= m || j < 0 || j >= n || grid[i][j] == 0) return ;
        int tmp = grid[i][j] ;
        sum += tmp ;
        ans = max (ans , sum) ;
        grid[i][j] = 0 ;
        dfs(i + 1 , j , sum , grid) ;
        dfs(i - 1 , j , sum , grid) ;
        dfs(i , j + 1 , sum , grid) ;
        dfs(i , j - 1 , sum , grid) ;
        sum -= tmp ;
        grid[i][j] = tmp ;
    }
    int getMaximumGold(vector<vector<int>>& grid) {
        int m = grid.size() , n = grid[0].size() ;
        for(int i = 0 ; i < m ; i ++){
            for(int j = 0 ; j < n ; j ++){
                if(grid[i][j] > 0){
                    dfs(i, j, 0, grid) ;
                }
            }
        }
        return ans ;
    }
};

确实这种简单的回溯没必要再搞 DIRECTION 和 BOOL 来做。

2.6 lc.1748 唯一元素的和

class Solution {
public:
    int sumOfUnique(vector<int>& nums) {
        int ans = 0 , len = nums.size() ;
        sort(nums.begin() , nums.end()) ;
        if(len == 1) return nums[0] ;
        if(nums[1] != nums[0]) ans = nums[0] ;
        if(nums[len - 1] != nums[len - 2]) ans += nums[len - 1] ;
        for(int i = 1 ; i < len - 1 ; i ++){
            if(nums[i] != nums[i - 1] && nums[i] != nums[i + 1]) ans += nums[i] ;
        }
        return ans ;
    }
};

2.8 lc.1001 网格照明

  • 模拟 WA
class Solution {
public:
    void openvisit(int row , int col , int n , vector<vector<int>>& open){
        for(int i = 0 ; i < n ; i ++){
            int sum = row + col , dif = col - row;
            open[row][i] = 1 ;
            open[i][col] = 1 ;
            int y1 = sum - i , y2 = i + dif;
            if(y1 >= 0 && y1 < n) open[i][y1] = 1 ;
            if(y2 >= 0 && y2 < n) open[i][y2] = 1 ;
        }
    } // 0 close, 1 light, 2 open
    void closevisit(int row , int col , int n , vector<vector<int>>& open){
        vector<vector<int>> direction = {{0,1},{0,-1},{1,0},{1,-1},{0,0},{1,1},{1,-1},{-1,1},{-1,-1}};
        for(int i = 0 ; i < 9 ; i ++){
            int pr = row + direction[i][0] , pc = col + direction[i][1] ;
            if(pr >= 0 && pr < n && pc >= 0 && pc < n){
                if(open[pr][pc] == 2) close(row , col , n , open) ;
            }
        }
    } 
    void close(int row , int col , int n , vector<vector<int>>& open){
        for(int i = 0 ; i < n ; i ++){
            int sum = row + col , dif = col - row;
            open[row][i] = 0 ;
            open[i][col] = 0 ;
            int y1 = sum - i , y2 = i + dif;
            if(y1 >= 0 && y1 < n) open[i][y1] = 0 ;
            if(y2 >= 0 && y2 < n) open[i][y2] = 0 ;
        }
    }
    vector<int> gridIllumination(int n, vector<vector<int>>& lamps, vector<vector<int>>& queries) {
        vector<int> ans ;
        vector<vector<int>> open (n , vector<int>(n , 0)) ;
        for(int i = 0 ; i < lamps.size() ; i ++){
            int row = lamps[i][0] , col = lamps[i][1] ;
            open[row][col] = 2 ;
            openvisit(row , col , n , open);
        }
        for(int i = 0 ; i < queries.size() ; i ++){
            int row = queries[i][0] , col = queries[i][1] ;
            if(open[row][col] != 0) ans.emplace_back(1) ;
            else ans.emplace_back(0) ;
            closevisit(row , col , n , open);
        }
        return ans ;
    }
};

一个位置只要亮了就是1,所以一个光源没了就不亮了,这个方法不成立。
写了不少时间,在写代码前进行算法分析还是有必要的。

  • 行列两个对角线共开 4 个哈希表
class Solution {
public:
    vector<int> gridIllumination(int n, vector<vector<int>>& lamps, vector<vector<int>>& queries) {
        set<pair<int, int> > point;
        map<int, int> r, c, d, rd;

        for (int i = 0; i < lamps.size(); i++) {
            int x = lamps[i][0], y = lamps[i][1];
            if (point.find({x, y}) == point.end()) {
                point.insert({x, y});
                r[x]++;
                c[y]++;
                d[x - y]++;
                rd[x + y]++;
            }
        }
      	
        vector<int> ans (queries.size());
        for (int i = 0; i < queries.size(); i++) {
            int x = queries[i][0], y = queries[i][1];
            if (r[x] || c[y] || d[x - y] || rd[x + y])
                ans[i] = 1;
            else
                ans[i] = 0;
            for (int rx = -1; rx <= 1; rx++) {
                for (int ry = -1; ry <= 1; ry++) {
                    int nx = x + rx, ny = y + ry;
                    if (point.find({ nx, ny}) != point.end()) {
                        cout << nx << ' ' << ny << endl;
                        point.erase({nx, ny});
                        r[nx]--;
                        c[ny]--;
                        d[nx - ny]--;
                        rd[nx + ny]--;
                    }
                }
            }
        }
        
        return ans;
    }
};

2.9 lc.2006 差绝对值为K的数对数目

  • sort + 二分查找
class Solution {
public:
    int ans = 0 ;
    void Findx(vector<int>& nums , int k , int x , int i){
        int l = i , r = nums.size() - 1 ;
        while(l < r){
            int mid = l + r >> 1;
            if(x <= nums[mid]) r = mid ;
            else l = mid + 1 ;
        }
        while(l < nums.size()){
            if(nums[l] == x) {
                ans ++ ;
                l ++;
            }
            else break ;
        }
    }
    int countKDifference(vector<int>& nums, int k) {
        int n = nums.size() ;
        sort(nums.begin() , nums.end()) ;
        for(int i = 0 ; i < n ; i ++){
            int x = nums[i] + k ;
            if(x > nums[n - 1]) break ;
            Findx(nums , k , x , i);
        }
        return ans ;
    }
};

ans 得注意每次迭代时值的迭代。

2.10 lc.1447 最简分数 int -> string: to_string

  • 居然没超时
class Solution {
public:
    bool huzhi(int j , int i){ // 判断两数是否互质 j 被除数 i 除数
        for(int x = 2 ; x < i ; x ++){
            if(i % x == 0 && j % x == 0) return false ;
        }
        return true ;
    }
    vector<string> simplifiedFractions(int n) {
        vector<string> ans ;
        for(int i = 2 ; i <= n ; i ++){
            for(int j = 1 ; j < i ; j ++){
                if(!huzhi(j,i)) continue;
                ans.emplace_back(to_string(j) + "/" + to_string(i)) ;
            }
        }
        return ans ;
    }
};

int 转 string to_string

2.11 lc.1984 学生分数最小差值

  • 滑动窗口
class Solution {
public:
    int minimumDifference(vector<int>& nums, int k) {
        int ans = 100000;
        sort(nums.begin() , nums.end()) ;
        int l = 0 , r = k - 1 ;
        while(r < nums.size()){
            int dis = nums[r] - nums[l] ;
            ans = min(ans , dis) ;
            r ++ ; l ++ ;
        }
        return ans ;
    }
};

2.12 lc.1020 飞地的数量

飞地 (enclave) 的意思是隶属于某一行政区管辖但不与本区毗连的土地。如果某一行政主体拥有一块飞地,那么它无法取道自己的行政区域到达该地,只能“飞”过其他行政主体的属地,才能到达自己的飞地。(百度百科)

  • DFS
class Solution {
public:
    void dfs(vector<vector<int>>& grid, int row, int col){
        int m = grid.size() , n = grid[0].size() ;
        if(row < 0 || row >= m || col < 0 || col >= n ) return ;
        if(grid[row][col] == 0 || grid[row][col] == 2) return ;
        else if(grid[row][col] == 1) grid[row][col] = 2 ;
        dfs(grid,row - 1,col);
        dfs(grid,row + 1,col);
        dfs(grid,row,col - 1);
        dfs(grid,row,col + 1);
    }
    int numEnclaves(vector<vector<int>>& grid) {
        int m = grid.size() , n = grid[0].size() , ans = 0 ;
        for(int i = 0 ; i < n ; i ++){
            if(grid[0][i] == 1) dfs(grid,0,i) ;
            if(grid[m-1][i] == 1) dfs(grid,m-1,i) ;         
        }
        for(int i = 0 ; i < m ; i ++){
            if(grid[i][0] == 1) dfs(grid,i,0) ;
            if(grid[i][n-1] == 1) dfs(grid,i,n-1) ;
        }

        for(int i = 0 ; i < m ; i ++){
            for(int j = 0 ; j < n ; j ++){
                if(grid[i][j] == 1) ans ++ ;
            }
        }

        return ans ;
    }
};

2.13 lc.1189 “气球”

class Solution {
public:
    int maxNumberOfBalloons(string text) {
        int b = 0 , a = 0 , l = 0 , o = 0 , n = 0 , ans = 0 ; 
        for(int i = 0 ; i < text.size() ; i ++){
            if(text[i] == 'b') b ++ ;
            if(text[i] == 'a') a ++ ;
            if(text[i] == 'l') l ++ ;
            if(text[i] == 'o') o ++ ;
            if(text[i] == 'n') n ++ ;
        }
        while( b > 0 && a > 0 && l > 1 && o > 1 && n > 0){
            ans ++ ;
            b -- ; a -- ; n -- ; l -= 2 ; o -= 2 ;
        }
        return ans ;
    }
};

2.14 lc.540 有序数组中的单一元素

模拟也行,用二分理论上更快

class Solution {
public:
    int singleNonDuplicate(vector<int>& nums) {
        int low = 0, high = nums.size() - 1;
        while (low < high) {
            int mid = (high - low) / 2 + low;
            mid -= mid & 1;
            if (nums[mid] == nums[mid + 1]) {
                low = mid + 2;
            } else {
                high = mid;
            }
        }
        return nums[low];
    }
};

2.18 lc.1791 找出星型图中心节点

class Solution {
public:
    int findCenter(vector<vector<int>>& edges) {
        if(edges[0][0] == edges[1][0]) return edges[0][0] ;
        else if(edges[0][0] == edges[1][1]) return edges[0][0] ;
        else if(edges[0][1] == edges[1][0]) return edges[0][1] ;
        else if(edges[0][1] == edges[1][1]) return edges[0][1] ;
        return 0 ;
    }
};

反正n大于等于3,edge前两项都判断一下。

2.19 lc.969 煎饼排序

class Solution {
public:
    vector<int> pancakeSort(vector<int>& arr) {
        vector<int> ret;
        for (int n = arr.size(); n > 1; n--) {
            int index = max_element(arr.begin(), arr.begin() + n) - arr.begin();
            if (index == n - 1) {
                continue;
            }
            reverse(arr.begin(), arr.begin() + index + 1);
            reverse(arr.begin(), arr.begin() + n);
            ret.push_back(index + 1);
            ret.push_back(n);
        }
        return ret;
    }
};

智商题属于是

2.20 lc.717 1bit&2bit

class Solution {
public:
    bool isOneBitCharacter(vector<int>& bits) {
        int i = 0 ;
        while(i < bits.size() - 1){
            if(bits[i] == 1) i += 2 ;
            else i ++ ; 
        }
        if(i == bits.size() - 1 ) return true ;
        else return false ;
    }
};

2.26 lc.2016 增量元素之间的最大差值

  • 滑动窗口
class Solution {
public:
    int maximumDifference(vector<int>& nums) {
        int ans = 0 ;
        int left = 0 , right = 0 , len = nums.size();
        while(left < len && right < len){
            if(nums[right] < nums[left]){
                left = right ;
            }
            ans = max (ans , nums[right] - nums[left]) ;
            right ++ ;
        }
        if(ans == 0) return -1 ;
        return ans ;    
    }
};

休息了好几天,开学了,继续奋斗继续刷题。

2.28 lc.1601 最多可达成的换楼请求数

  • dfs
class Solution {
private:
    vector<int> delta;
    int ans = 0, cnt = 0, zero, n;

public:
    void dfs(vector<vector<int>> &requests, int pos) {
        if (pos == requests.size()) {
            if (zero == n) {
                ans = max(ans, cnt);
            }
            return;
        }

        // 不选 requests[pos]
        dfs(requests, pos + 1);

        // 选 requests[pos]
        int z = zero;
        ++cnt;
        auto &r = requests[pos];
        int x = r[0], y = r[1];
        zero -= delta[x] == 0;
        --delta[x];
        zero += delta[x] == 0;
        zero -= delta[y] == 0;
        ++delta[y];
        zero += delta[y] == 0;
        dfs(requests, pos + 1);
        --delta[y];
        ++delta[x];
        --cnt;
        zero = z;
    }

    int maximumRequests(int n, vector<vector<int>> &requests) {
        delta.resize(n);
        zero = n;
        this->n = n;
        dfs(requests, 0);
        return ans;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值