Leetcode面试热题(九)

本文分享了作者社招面试中遇到的LeetCode和牛客网上大公司的高频算法题,涵盖背包问题、DFS、BFS、动态规划等,推荐100道热门题目供考生有选择地刷题,并建议在官方平台查看优秀解法。
摘要由CSDN通过智能技术生成

       如今不论是校招还是社招,大多数公司都会有笔试+面试的算法题,以此来考察候选人的数据结构和算法能力,因此我们面试前最好复习下算法,简单来说就是刷题呗!

        以下是本人社招时在Leetcode和牛客网上的大厂的高频题,大概二三百道,此系列只列出最热门的一百来道,代码都是Leetcode上的,可以正常运行。大家可以根据下面推荐的题目来有选择的刷题,最好是进入Leetcode或牛客来刷,里面有许多优秀解法可以参考!

        常见算法有背包、DFS、BFS、动态规划、数组、状态压缩、图优化、数学推导、字符串、链表二叉树、邻接表、图优化等等。

        下面是正常的题目,大家可以参考一下:

//2021.04.28

1、全排列II----有重复数字的全排列数组
class Solution {
private:
    vector<vector<int>> result;
    vector<int> path;
    void backtracking (vector<int>& nums, vector<bool>& used) {
        // 此时说明找到了一组
        if (path.size() == nums.size()) {
            result.push_back(path);
            return;
        }
        for (int i = 0; i < nums.size(); i++) {
            // used[i - 1] == true,说明同一树支nums[i - 1]使用过
            // used[i - 1] == false,说明同一树层nums[i - 1]使用过
            // 如果同一树层nums[i - 1]使用过则直接跳过
            if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
                continue;
            }
            if (used[i] == false) {
                used[i] = true;
                path.push_back(nums[i]);
                backtracking(nums, used);
                path.pop_back();
                used[i] = false;
            }
        }
    }
public:
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        result.clear();
        path.clear();
        sort(nums.begin(), nums.end()); // 排序
        vector<bool> used(nums.size(), false);
        backtracking(nums, used);
        return result;
    }
};


作者:carlsun-2
链接:https://leetcode-cn.com/problems/permutations-ii/solution/47-quan-pai-lie-iiche-di-li-jie-pai-lie-zhong-de-q/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。



2、滑动窗口最大值

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        int n = nums.size();
        deque<int> q;
        for (int i = 0; i < k; ++i) {
            while (!q.empty() && nums[i] >= nums[q.back()]) {
                q.pop_back();
            }
            q.push_back(i);
        }

        vector<int> ans = {nums[q.front()]};
        for (int i = k; i < n; ++i) {
            while (!q.empty() && nums[i] >= nums[q.back()]) {
                q.pop_back();
            }
            q.push_back(i);
            while (q.front() <= i - k) {
                q.pop_front();
            }
            ans.push_back(nums[q.front()]);
        }
        return ans;
    }
};

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/sliding-window-maximum/solution/hua-dong-chuang-kou-zui-da-zhi-by-leetco-ki6m/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

3、加起来和为目标值的组合——多种都可以

class Solution {
public:
    vector<vector<int> > combinationSum2(vector<int> &num, int target) {
        vector<vector<int> > res;
        vector<int> tmp;
        if (num.empty()) return res;
        sort(num.begin(), num.end());
        dfs(num, target, res, tmp, 0);
        return res;
    }

    void dfs(vector<int> &num, int target, vector<vector<int> > &res, vector<int> &tmp, int start) {
        if (target == 0) {
            res.push_back(tmp);
            return;
        }
        if (start >= num.size()) return;
        for (int i = start; i < num.size(); ++i) {
            if (i > start && num[i] == num[i-1]) continue;  // 去重
            if (num[i] <= target) {                         // 剪枝
                tmp.push_back(num[i]);
                dfs(num, target - num[i], res, tmp, i + 1);
                tmp.pop_back();
            }
        }
    }
};

https://www.nowcoder.com/practice/75e6cd5b85ab41c6a7c43359a74e869a?tpId=117&tqId=37742&rp=1&ru=%2Fta%2Fjob-code-high&qru=%2Fta%2Fjob-code-high%2Fquestion-ranking&tab=answerKey


4、最长有效括号
class Solution {
public:
    int longestValidParentheses(string s) {
        int left = 0, right = 0, maxlength = 0;
        for (int i = 0; i < s.length(); i++) {
            if (s[i] == '(') {
                left++;
            } else {
                right++;
            }
            if (left == right) {
                maxlength = max(maxlength, 2 * right);
            } else if (right > left) {
                left = right = 0;
            }
        }
        left = right = 0;
        for (int i = (int)s.length() - 1; i >= 0; i--) {
            if (s[i] == '(') {
                left++;
            } else {
                right++;
            }
            if (left == right) {
                maxlength = max(maxlength, 2 * left);
            } else if (left > right) {
                left = right = 0;
            }
        }
        return maxlength;
    }
};

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-valid-parentheses/solution/zui-chang-you-xiao-gua-hao-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。




//2021.05.07

5、丢棋子问题
https://www.nowcoder.com/practice/d1418aaa147a4cb394c3c3efc4302266?tpId=117&tqId=37844&rp=1&ru=%2Fta%2Fjob-code-high&qru=%2Fta%2Fjob-code-high%2Fquestion-ranking&tab=answerKey
https://www.cnblogs.com/willwuss/p/12256475.html
/*
设P(N,K)的返回值时N层楼时有K个棋子在最差的情况下仍的最少次数。

(1)如果N==0,棋子在第0层肯定不会碎,所以P(0, K) = 0;
(2)如果K==1,楼层有N层,只有1个棋子,故只能从第一次开始尝试,P(N,1)=N;
(3)对于N>0且K>1, 我们需考虑第1个棋子是从那层开始仍的。如果第1个棋子从第i层开始仍,那么有以下两种情况:
	1) 碎了。没必要尝试第i层以上的楼层了,接下来的问题就变成了剩下i-1层楼和K-1个棋子,所以总步数为 1+P(i-1, K-1);
	2)没碎。 那么可以知道没必要尝试第i层及其以下的楼层了,接下来的问题就变成了还剩下N-i层和K个棋子,所以总步数为 1+P(N-i, K).
(4)根据题意应该选取(1)和(2)中较差的那种情况,即 max{ P(i-1, K-1), P(N-i, K)}+1。 由于i的取值范围是 1到N, 
那么步数最少的情况为, P(N, K)=min{ max{P(i-1, K-1), P(N-i, K)}(1<=i<=N) }+1。


通过研究以上递归函数发现, P(N, K)过程依赖于P(0...N-1, K-1) 和 P(0...N-1, K)。所以,若把所有的递归的返回值看作是一个二维数组,可以用动态规划的方法优化递归过程。从而减少计算量。
  dp[0][K] = 0, dp[N][1] = N, dp[N][K] = min( max(dp[i-1][K-1], dp[N-i][K])) + 1。
*/
(1)时间复杂度 O(N^2 * K)
public int solutionTwo(int N, int K){
	if ( N<1 || K<1 ) 
		return 0;
	if ( K == 1 ) return N;
	int[][] dp = new int[N+1][K+1];
	for(int i=1; i<dp.length; ++i) {
		dp[i][1] = i;
	}
	for(int i=1; i<dp.length; ++i) {
		for(int j=2; j<=K; ++j) {
			int min = Integer.MAX_VALUE;
			for(int k=1; k<i+1; ++k) {
				min = Math.min(min, Math.max(dp[k-1][j-1], dp[i-k][j]));
			}
			dp[i][j] = min + 1;
		}
	}
	return dp[N][K];
}

(2)map[i][j]的意义为i个棋子仍j次最多搞定的楼层数
/*
 通过研究map表发现,第一排的值从左到有一次为1,2,3...,第一纵列都为0, 初次之外的其他位置(i, j),都有 map[i][j] == map[i][j-1] + map[i-1][j-1] + 1.
  将设i个棋子仍j次最多搞定m层楼,“搞定最多”说明每次仍的位置都是最优的且在棋子肯定够用的情况下,若第1个棋子仍在a层楼是最优的。
  1. 如果第1个棋子以碎,那么就向下,看i-1个棋子扔j-1次最多搞定多少层楼;
  2. 如果第1个棋子没碎,那么就向上,看i个棋子扔j-1次最多搞定多少层楼;
  3. a层楼本身也是被搞定的1层;
  1、2、3的总楼数就是i个棋子扔j次最多搞定的楼数,map表的生成过程极为简单,同时数值增长的极快。原始问题可以通过map表得到很好的解决。
*/



6、最长连续序列
class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        unordered_set<int> num_set;
        for (const int& num : nums) {
            num_set.insert(num);
        }

        int longestStreak = 0;

        for (const int& num : num_set) {
            if (!num_set.count(num - 1)) {
                int currentNum = num;
                int currentStreak = 1;

                while (num_set.count(currentNum + 1)) {
                    currentNum += 1;
                    currentStreak += 1;
                }

                longestStreak = max(longestStreak, currentStreak);
            }
        }

        return longestStreak;           
    }
};


//2021.05.10
7、二叉树的直径
class Solution {
public:
    int res=0;//答案
    int dfs(TreeNode* p,int d){
        if(!p) return 0;//结束递归的条件
        int dl=dfs(p->left,d+1);//该节点左子树高度
        int dr=dfs(p->right,d+1);//该节点右子树高度
        res=max(res,dr+dl);//此次递归该做的事
        return max(dl,dr)+1;//此次递归返回的该节点高度
    }
    
    int diameterOfBinaryTree(TreeNode* root) {
        dfs(root,0);
        return res;
    }
}


8、最大数(一个数组中的数字进行拼接,返回一个数值最大的字符串)
class Solution {
public:
    string largestNumber(vector<int>& nums) {
        vector<string> str;
        for(auto i : nums) {
            str.push_back(to_string(i));
        }
        // 使用 lambda 比较 elements.
        auto cmp = [](string left, string right) {
            return left + right > right + left;
        };
        sort(str.begin(),str.end(), cmp);
        stringstream ss;
        for(auto c : str) {
            ss << c;
        }
        string ans = ss.str();
        if(ans[0] == '0'){
            return "0";
        }
        return ans;
    }
};

作者:AC_OIer
链接:https://leetcode-cn.com/problems/largest-number/solution/gong-shui-san-xie-noxiang-xin-ke-xue-xi-vn86e/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


9、大数乘法——返回字符串
https://www.nowcoder.com/practice/c4c488d4d40d4c4e9824c3650f7d5571?tpId=117&tqId=37843&rp=1&ru=%2Fta%2Fjob-code-high&qru=%2Fta%2Fjob-code-high%2Fquestion-ranking&tab=answerKey
string solve(string s, string t) {
        // write code here
        int n = s.size(), m = t.size();
        vector<int> res(n + m, 0);
        for (int i = 0; i < n; i ++)
            for (int j = 0; j < m; j ++)
                res[i + j + 1] += (s[i] - '0') * (t[j] - '0');
        
        for (int i = res.size() - 1; i > 0; i --)
        {
            if (res[i] >= 10)
            {
                res[i - 1] += res[i] / 10;
                res[i] %= 10;
            }
        }
        string ss = "";
        for (int i = 0; i < res.size(); i ++)
        {
            if (i == 0 && res[i] == 0) continue;
            ss += to_string(res[i]);
        }
        return ss;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值