之前总结过字节跳动TOP50算法面试题:
字节跳动常见算法面试题top50整理_沉迷单车的追风少年-CSDN博客_字节算法面试题
回溯
46.全排列
class Solution {
private:
vector<vector<int> > ans;
void dfs(vector<int>& nums, vector<int>& temp, int index) {
if (temp.size() == nums.size()) {
ans.push_back(temp);
return;
}
for (int i = 0; i < nums.size(); i++) {
if (find(temp.begin(), temp.end(), nums[i]) == temp.end()) {
temp.push_back(nums[i]);
dfs(nums, temp, i);
temp.pop_back();
}
}
}
public:
vector<vector<int>> permute(vector<int>& nums) {
vector<int> temp;
dfs(nums, temp, 0);
return ans;
}
};
78.子集
class Solution {
private:
vector<vector<int> > ans;
void dfs(vector<int>& nums, vector<int>& temp, int index) {
if (find(ans.begin(), ans.end(), temp) == ans.end()) {
ans.push_back(temp);
}
if (index >= nums.size()) {
return;
}
for (int i = index; i < nums.size(); i++) {
temp.push_back(nums[i]);
dfs(nums, temp, i + 1);
temp.pop_back();
}
}
public:
vector<vector<int>> subsets(vector<int>& nums) {
vector<int> temp;
dfs(nums, temp, 0);
return ans;
}
};
17.电话号码的字母组合
class Solution {
private:
vector<string> ans;
vector<string> sList={"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"}; //字符表
void backtrack(string& digits, string temp, int index) {
if (index == digits.size()) {
ans.push_back(temp);
return;
}
string s = sList[digits[index] - '0'];
// for循环横向遍历,递归纵向遍历
for (int i = 0; i < s.size(); i++) {
temp.push_back(s[i]);
backtrack(digits, temp, index + 1);
temp.pop_back();
}
}
public:
vector<string> letterCombinations(string digits) {
if (digits.empty()) {
return {};
}
backtrack(digits, {}, 0);
return ans;
}
};
39.组合总和
class Solution {
private:
vector<vector<int> > ans;
void backtrack(vector<int>& candidates, int& target, vector<int> temp, int cursum, int index) {
if (cursum == target) {
ans.push_back(temp);
return;
}
for (int i = index; i < candidates.size(); i++) {
// 剪枝
if (cursum + candidates[i] > target) {
break;
}
temp.push_back(candidates[i]);
backtrack(candidates, target, temp, cursum + candidates[i], i);
temp.pop_back();
}
}
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());
backtrack(candidates, target, {}, 0, 0);
return ans;
}
};
22.括号生成
class Solution {
private:
vector<string> ans;
void backtrack(int left, int right, int n, string s) {
if (left == n && right == n) { // 左右都拼完了终止
ans.push_back(s);
return;
}
if (left < n) { // 左边括号没拼满拼接左边
backtrack(left + 1, right, n, s + '(');
}
if (right < left) { // 右边括号比左边少拼接右边
backtrack(left, right + 1, n, s + ')');
}
}
public:
vector<string> generateParenthesis(int n) {
// DFS+回溯
// left代表左边拼了的括号数
// right代表右边拼的括号数
backtrack(0, 0, n, "");
return ans;
}
};
79.单词搜索
class Solution {
private:
// 剪枝操作,当找到路径的时候终止
bool flag = false;
public:
bool exist(vector<vector<char>>& board, string word) {
if (board.empty() || board.size() == 0 || board[0].size() == 0)
return false;
// DFS+回溯+剪枝
for (int i = 0; i<board.size(); i++) {
for (int j = 0; j<board[0].size(); j++) {
if (dfs(board, i, j, word, 0))
return true;
}
}
return false;
}
// 传入引用直接在原位置上进行操作,不需要新建变量与赋值,节省时间开销和空间开销
bool dfs(vector<vector<char>>& board, int i, int j, const string& word, int cur) {
// 先列出终止条件
if (cur == word.size()) {
flag = true;
return true;
}
// 回溯中心处理环节
if (i < 0 || i>=board.size() || j < 0 || j >= board[0].size() || word[cur] != board[i][j])
return false;
// 分别标记上下左右每次搜索是否成功
bool flag1, flag2, flag3, flag4;
if (!flag) {
// 先将board[i][j]拿出来用
board[i][j] = '.';
flag1 = dfs(board, i+1, j, word, cur+1);
flag2 = dfs(board, i-1, j, word, cur+1);
flag3 = dfs(board, i, j+1, word, cur+1);
flag4 = dfs(board, i, j-1, word, cur+1);
// 再将board[i][j]放回去,还原回溯现场
board[i][j] = word[cur];
// 任意一个方向成功即为此处搜索成功,返回true
return flag1 ||flag2 || flag3 || flag4;
}
return true;
}
};
131.分割回文串
class Solution {
public:
vector<vector<string>> partition(string &s) {
backtravel(s, 0, s.size()-1);
return ans;
}
private:
vector<vector<string> > ans;
vector<string> temp;
void backtravel(const string &s, const int &left, const int &right) {
//到字符串末尾了,将本次结果记录下来
if (left > right) {
ans.push_back(temp);
return;
}
//从index为a开始截取长度为1,2,3..的子串进行验证,成功则用剩下的部分递归
for (int i = 1; i <= right - left + 1; i++) {
if (isHuiwen(s.substr(left, i))) {
temp.push_back(s.substr(left, i));
// 以上一次成功的位置为起点再次进行递归
backtravel(s, left+i, right);
temp.pop_back();
}
}
}
bool isHuiwen(const string &s) {
int left = 0, right = s.size() - 1;
while (left <= right) {
if (s[left] != s[right])
return false;
left++;
right--;
}
return true;
}
};
51.N皇后
class Solution {
private:
vector<vector<string>> ans;
// n 为输入的棋盘大小
// row 是当前递归到棋盘的第几行了
void backtrack(int n, int row, vector<string> chessboard) {
if (row == n) {
ans.push_back(chessboard);
return;
}
for (int col = 0; col < n; col++) {
if (isVaild(chessboard, row, col)) {
chessboard[row][col] = 'Q';
backtrack(n, row + 1, chessboard);
chessboard[row][col] = '.';
}
}
}
// 判断是否合法
bool isVaild(vector<string> chessboard, int row, int col) {
// 同列不能用皇后
for (int i = 0; i < row; i++) {
if (chessboard[i][col] == 'Q') {
return false;
}
}
// 斜45不能用皇后
for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
if (chessboard[i][j] == 'Q') {
return false;
}
}
// 斜135不能用皇后
for (int i = row - 1, j = col + 1; i >= 0 && j < chessboard.size(); i--, j++) {
if (chessboard[i][j] == 'Q') {
return false;
}
}
return true;
}
public:
vector<vector<string>> solveNQueens(int n) {
vector<string> chessboard(n, string(n, '.'));
backtrack(n, 0, chessboard);
return ans;
}
};
二分搜索
35.搜索插入位置
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] < target) {
left = mid + 1;
} else {
return mid;
}
}
return right + 1;
}
};
74.搜索二维矩阵
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
// 选择左下角开始比较
if(matrix.size()==0)
return false;
int i = 0;
int j = matrix[0].size()-1;
while (i<matrix.size()&&j>=0) {
if ( matrix[i][j]>target ) {
j--;
}else if (matrix[i][j]<target) {
i++;
}else {
return true;
}
}
return false;
}
};
34.在排序数组中查找元素的第一个和最后一个位置
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int leftBorder = getLeftBorder(nums, target);
int rightBorder = getRightBorder(nums, target);
// 情况一: target在数组范围的左边或者右边
if (leftBorder == -2 || rightBorder == -2) {
return {-1, -1};
}
// 情况三: target在数组范围内且存在
if (rightBorder - leftBorder > 1) {
return {leftBorder + 1, rightBorder - 1};
}
// 情况二: target在数组范围内但是不存在
return {-1, -1};
}
private:
int getRightBorder(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
int rightBorder = -2; // 记录一下rightBorder没有被赋值的情况
while (left <= right) {
int middle = left + ((right - left) / 2);
if (nums[middle] > target) {
right = middle - 1;
} else { // 寻找右边界,nums[middle] == target的时候更新left
left = middle + 1;
rightBorder = left;
}
}
return rightBorder;
}
int getLeftBorder(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
int leftBorder = -2; // 记录一下leftBorder没有被赋值的情况
while (left <= right) {
int middle = left + ((right - left) / 2);
if (nums[middle] >= target) { // 寻找左边界,nums[middle] == target的时候更新right
right = middle - 1;
leftBorder = right;
} else {
left = middle + 1;
}
}
return leftBorder;
}
};
33.搜索旋转排序数组
class Solution {
public:
int search(vector<int>& nums, int target) {
int ans = -1;
// 二分
// 将数组一分为二,其中一定有一个是有序的,另一个可能是有序,也能是部分有序。此时有序部分用二分法查找。无序部分再一分为二,其中一个一定有序,另一个可能有序,可能无序。就这样循环.
int left = 0;
int right = nums.size() - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] > nums[right]) { // 无序在右半段
if (target < nums[mid] && target >= nums[left]) { // 判断target是否在有序的半段
right = mid - 1;
} else {
left = mid + 1;
}
} else { // 无序在左半段
if (target > nums[mid] && target <= nums[right]) { // 判断target是否在有序的半段
left = mid + 1;
} else {
right = mid - 1;
}
}
}
return ans;
}
};
153.寻找旋转排序数组中的最小值
class Solution {
public:
int findMin(vector<int>& nums) {
int left = 0;
int right = nums.size() - 1;
while (left < right) {
// 取中间值
int mid = (right + left) / 2;
// 如果中间值小于最大值,则最大值减小
if (nums[mid] < nums[right]) {
right = mid;
} else { // 如果中间值大于最大值,则最小值变大
left = mid + 1;
}
}
return nums[left];
}
};