leetcode 71-80

LeetCode 71. 简化路径(华为2020.9秋招面试第2题)

分析

先对path路径按'/'分隔, 进行扫描,
当不是'/'的时候加入到当前扫描的的字符串name
如果是'/', 那么需要分情况加入到答案数组res中,

  1. 如果前面扫描出来的当前name == "..", 那么需要将res最后一个'\'前的目录连带'\'弹出
  2. 如果扫描出的来name是个目录, 并且name不是 原地不动'.' 并且 目录不是\\, \\会造成name为空, 那么res += name
    此时操作完, 需要将name清空.

code

class Solution {
    
    
public:
    string simplifyPath(string path) {
    
    
        string res, name; // res 表示答案, name表示当前取到的目录名 
        // 方向 ->
        if (path.back() != '/')  path += '/';
        for (auto c : path){
    
    
            if (c != '/') name += c;
            else {
    
    
                if (name == ".."){
    
    
                    while (res.size() && res.back() != '/') res.pop_back();//将当前目录的文件名去掉
                    if (res.size()) res.pop_back(); //将文件名前面的/去掉
                }else if (name != "." && name != "") {
    
     //name != ""是因为会出现//这种情况 //字符的话 name会为“”, 直接不处理即可, “.”也同样不处理
                    res += '/' + name; // 追加正确的目录'/' + name
                }
                name.clear();// 因为else 这个分支处理完了name, 所以需要清空
            }
        }

        if (res.empty()) res = "/";
        return res;
    }
};

LeetCode 72. 编辑距离

分析

经典dp模版题
f[i][j] 表示s1前i个字符 和 s2前j个字符匹配最少的操作步数
:s1删除一个元素,使得s1[1 ~ i]和s2[1 ~ j]匹配, 那么在删除操作之前 s1[1 ~ i - 1] 已经和s2[1 ~ j]匹配, 因此前一步是f[i - 1][j]
:s1增加一个元素, 使得s1[1 ~ i]和s2[1 ~ j]匹配, 在s1[i]后增加一个元素匹配s2[1 ~ j], 那么增加的元素必定是s2[j], 那么在增加元素之前, s1[1 ~ i]只能匹配s2[1 ~ j - 1], 因此前一步是f[i][j - 1]
: s1修改一个元素, 使得s1[1 ~ i]和s2[1 ~ j]匹配. 那么修改之前, s1[1 ~ i - 1] 匹配s2[1 ~ j - 1], , 因此前一步是f[i - 1][j - 1]
综上, 如果s1[i] != s2[j], 那么f[i][j] = min(f[i - 1][j], min(f[i][j - 1], f[i - 1][j - 1])) + 1

code

class Solution {
    
    
public:
    int minDistance(string word1, string word2) {
    
    
        int n = word1.size(), m = word2.size();
        word1 = ' ' + word1, word2 = ' ' + word2;
        vector<vector<int>> f(n + 1, vector<int>(m + 1));
        for (int i = 1; i <= n; i ++ ) f[i][0] = i;
        for (int i = 1; i <= m; i ++ ) f[0][i] = i;
        for (int i = 1; i <= n; i ++ )
            for (int j = 1; j <= m; j ++ )
                if (word1[i] == word2[j]) f[i][j] = f[i - 1][j - 1];
                else f[i][j] = min(f[i - 1][j], min(f[i][j - 1], f[i - 1][j - 1])) + 1;
        return f[n][m];
    }
};

LeetCode 73. 矩阵置零

分析

原地算法, 分别用矩阵的当前行, 记录当前行每个元素所在的列是否存在0,
第0行, 第0列额外用r0, c0标记
在这里插入图片描述

code

class Solution {
    
    
public:
    void setZeroes(vector<vector<int>>& matrix) {
    
    
        if (matrix.empty() || matrix[0].empty()) return ;
        int n = matrix.size(), m = matrix[0].size();
        int r0 = 1, c0 = 1;
        for (int i = 0; i < m; i ++ ) if (!matrix[0][i]) r0 = 0;
        for (int i = 0; i < n; i ++ ) if (!matrix[i][0]) c0 = 0;

        for (int i = 1; i < m; i ++ )
            for (int j = 1; j < n; j ++ )
                if (!matrix[j][i]) matrix[0][i] = 0;
        
        for (int i = 1; i < n; i ++ )
            for (int j = 1; j < m; j ++ )
                if (!matrix[i][j]) matrix[i][0] = 0;

        for (int i = 1; i < m; i ++ )
            if (!matrix[0][i])
                for (int j = 1; j < n; j ++ )
                    matrix[j][i] = 0;
        for (int i = 1; i < n; i ++ )
            if (!matrix[i][0])
                for (int j = 1; j < m; j ++ )
                    matrix[i][j] = 0;

        if (!r0) for (int i = 0; i < m; i ++ ) matrix[0][i] = 0;
        if (!c0) for (int i = 0; i < n; i ++ ) matrix[i][0] = 0;
    }
};

LeetCode 74. 搜索二维矩阵

分析

转为1维去搜索, 1维转2维 x坐标 / m, y坐标 %m.

code

class Solution {
    
    
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
    
    
        int n = matrix.size(), m = matrix[0].size();
        int l = 0, r = n * m - 1;
        while (l < r){
    
    
            int mid = l + r >> 1;
            if (matrix[mid / m][mid % m] >= target) r = mid;
            else l = mid + 1;
        }
        return matrix[l / m][l % m] == target;
    }
};

LeetCode 75. 颜色分类 (2020.8 百度提前批面试题)

分析

在这里插入图片描述

code

class Solution {
    
    
public:
    void sortColors(vector<int>& a) {
    
    
        for (int i = 0, j = 0, k = a.size() - 1; i < k;){
    
    
            if (a[i] == 0) swap(a[i ++], a[j ++ ]);
            else if (a[i] == 2) swap(a[i], a[k -- ]);
            else i ++;
        }
    }
};

LeetCode 76. 最小覆盖子串

分析

枚举每个终点i, 找到离i最近的距离j, 使得[j, i]之间包含t的所有字符
因为用的是双指针, 必须保证i往后移动, j不会往前走
证明:
如果i往后移动变成i', j不可能往前走到j', 因为[j,i]已经包含t的所有字符,因此[j, i’]也包含t的所有字符, 题目要求最短的包含t的长度, 因此j'至少得在j的位置

在这里插入图片描述
如何统计[j,i]中t中包含的字符数量, 用cnt表示有效(窗口中出现, t内也出现, 且窗口中字符个数不超过t中对应的字符个数)的字符个数(???, 说人话)
如下图:
t中如果有4个a, 如果当前窗口已经有4个a, 再加入1个a, 那么新加的这个a, 是无效的a, 因此有效字符个数cnt不变
在这里插入图片描述
反之, 如果t内需要有5个a, 窗口只有3个a, 再加1个a, 此时的a是有效的,
cnt ++
在这里插入图片描述
问题3 :
什么时候j可以往后移动?
ans : 如果窗口中a[j]出现的次数 > t内包含的a[j]的次数, 说明a[j]多余, 可以往后移动;反之, a[j]出现的次数 <= t内包含的a[j]的次数, 则不能往后移动, 因此往后移动a[j]的次数就少了, 不能包含t内所有字符了.

联动 leetcode3(同样的方法)

code

class Solution {
    
    
public:
    string minWindow(string s, string t) {
    
    
        unordered_map<char, int> hs, ht;
        for (auto c : t) ht[c] ++;

        int cnt = 0;
        string res;
        for (int i = 0, j = 0; i < s.size(); i ++ ){
    
    
            hs[s[i]] ++;
            if (hs[s[i]] <= ht[s[i]]) cnt ++;
            
            while (hs[s[j]] > ht[s[j]]) hs[s[j ++ ]] --;

            if (cnt == t.size())
                if (res.empty() || i - j + 1 < res.size())
                    res = s.substr(j, i - j + 1);
        }
        return res;
    }
};

LeetCode 77. 组合

分析

递归树如图
在这里插入图片描述
注意递归的结束条件 : path.size() == k

code

class Solution {
    
    
public:
    int _n;
    vector<vector<int>> res;
    vector<int> path;
    vector<vector<int>> combine(int n, int k) {
    
    
        _n = n;
        dfs(1, k);
        return res;
    }
    void dfs(int u, int k){
    
    
        if (path.size() == k){
    
    
            res.push_back(path);
            return ;
        }

        for (int i = u; i <= _n; i ++ ){
    
    
            path.push_back(i);
            dfs(i + 1, k);
            path.pop_back();
        }
    }
};

LeetCode 78. 子集

分析

原理同上一题

code

class Solution {
    
    
public:
    vector<vector<int>> res;
    vector<int> path;
    vector<vector<int>> subsets(vector<int>& nums) {
    
    
        for (int i = 0; i <= nums.size(); i ++ )
            dfs(nums, 0, i);
        return res;
    }

    void dfs(vector<int>& nums, int u, int k){
    
    
        if (path.size() == k){
    
    
            res.push_back(path);
            return ;
        }

        for (int i = u; i < nums.size(); i ++ ){
    
    
            path.push_back(nums[i]);
            dfs(nums, i + 1, k);
            path.pop_back();
        }
    }
};

LeetCode 79. 单词搜索

分析

枚举每个起点递归搜索, 如果一个起点, 能够搜到, 直接返回true
否则, 返回false

code

class Solution {
    
    
public:
    int dx[4] = {
    
    -1, 0, 1, 0}, dy[4] = {
    
    0, 1, 0, -1};
    bool exist(vector<vector<char>>& board, string word) {
    
    
        int n = board.size(), m = board[0].size();
        for (int i = 0; i < n; i ++ )
            for (int j = 0; j < m; j ++ )
                if (dfs(board, word, 0, i, j)) return true;
        return false;
    }
    bool dfs(vector<vector<char>>& board, string word, int u, int x, int y){
    
    
        if (board[x][y] != word[u]) return false;
        if (u == word.size() - 1) return true; // 此时当前的board[x][y] == word[u], 且u是word.size() - 1了

        char t = board[x][y];
        board[x][y] = '.'; // 防止走回头路
        for (int i = 0; i < 4; i ++ ){
    
    
            int a = x + dx[i], b = y + dy[i];
            if (a < 0 || a >= board.size() || b < 0 || b >= board[0].size() || board[a][b] == '.') continue;
            if (dfs(board, word, u + 1, a, b)) return true;
        }
        board[x][y] = t;
        return false;
    }
};

LeetCode 80. 删除排序数组中的重复项 II

分析

双指针算法
i表示当前扫描扫第几个数, k表示当前的有效数字

  1. 每次怎么判断a[i]是否有效?
    ans : 在有效的[0, k - 1]判断 a[i]出现了几次, 如果a[i]出现的次数 < 2, 那么a[i]是有效的, 可以放到有效的[0, k]内, 如果a[i]出现的次数 >= 2, 那么直接跳过, 因为此时a[i]再放进去, 就超过2个相同数字了
  2. 怎么判断[0, k - 1] a[i]有几个?
    ans : 总的序列有序, 并且因为有效的[0, k - 1]也是有序的, a[i]是当前枚举到的最大一个数, 如果[0, k]内有a[i]的话, 一定是在最后的位置附近. 所以只需要判断下, [0, k - 1]最后2个位置 是不是a[i]即可. 如果后2个是a[i], 那么可以跳过, 如果有一个不是a[i], 说明a[i]是有效的.
    因此整个数组扫描一遍 O ( n ) O(n) O(n).
    在这里插入图片描述

联动leetcode 26

code

class Solution {
    
    
public:
    int removeDuplicates(vector<int>& nums) {
    
    
        int k = 0;
        for (auto x : nums)
            if (k < 2 || (nums[k - 1] != x || nums[k - 2] != x))
                nums[k ++] = x;
        return k;
    }
};

猜你喜欢

转载自blog.csdn.net/esjiang/article/details/114378760
今日推荐