动态规划
给你一个可装载重量为W
的背包和N
个物品,每个物品有重量和价值两个属性。其中第i
个物品的重量为wt[i]
,价值为val[i],现在让你用这个背包装物品,最多能装的价值是多少?
int knapsack(int W, vector<int>& wt, vector<int>& val){
//vector全填入0,base case已初始化
vector<vector<int>> dp(N + 1, vector<int>(N+1, 0));
for(int i = 1; i <= N; i++){
for(int w = 1; w <= W; w++){
if(W - wt[w] < 0)
dp[i][w] = dp[i - 1][w];
else dp[i][w] = max(dp[i-1][w], dp[i-1][w-wt[i-1]] + val[i-1]);
}
}
}
排序数组中的搜索问题,首先想到二分搜索
二分查找
int binary_search(const int arr[], int start, int end, int key){
int res = -1;
int mid;
while(start <= end){
mid = begin + (end - begin) / 2;
if(arr[mid] == key){
res = mid;
return res;
}
else if(arr[mid] < key)
start = mid + 1;
else if(arr[mid] > key)
end = mid - 1;
}
return res; //单一出口
}
查找第一个大于等于target的索引
//查找第一个大于等于target的索引
//如果target存在,就是查找第一个等于target的位置
//如果不存在,就是第一个大于target的位置
int binarySearch(vector<int> arr, int target){
int len = arr.size();
if(arr[len - 1] < target) //特判
return -1;
int l = 0, r = len - 1;
while(l < r){
int m = l + (r - l) / 2;//向下取整
if(arr[m] < target)
l = m + 1;
else
r = m;
//这里包含了两种情况
}
退出的时候是r==l
return l;
}
};
查找最后一个大于等于target的索引
//查找最后一个大于等于target的索引
//如果target存在,就是查找最后一个等于target的位置
//如果不存在,就是第一个大于target的位置
int searchRight(vector<int>& nums, int target){
int i = 0, j = nums.size() - 1;
while(i < j){
int mid = i + (j - i + 1) / 2; //注意这里要+1,即向上取整
if(nums[mid] == target){
i = mid;
}
else if(nums[mid] > target){
j = mid - 1;
}
else{ //nums[mid] < target
i = mid + 1;
}
}
return i;
}
统计一个数字在排序数组中出现的次数
- 先找到该数字出现的第一个位置即
leftIndex
, 再找到出现的最后一个位置即rightIndex
,最后长度即为rightIndex - leftIndex + 1
;
class Solution {
public:
int searchLeft(vector<int>& nums, int target){
int i = 0, j = nums.size() - 1;
while(i < j){
int mid = i + (j - i) / 2;
if(nums[mid] == target){
j = mid;
}
else if(nums[mid] > target){
j = mid - 1;
}
else{ //nums[mid] < target
i = mid + 1;
}
}
if(nums[i] == target) return i;
return -1;
}
int searchRight(vector<int>& nums, int target){
int i = 0, j = nums.size() - 1;
while(i < j){
int mid = i + (j - i + 1) / 2;
if(nums[mid] == target){
i = mid;
}
else if(nums[mid] > target){
j = mid - 1;
}
else{ //nums[mid] < target
i = mid + 1;
}
}
//注意这里直接返回i,因为既然leftIndex存在,则rightIndex也一定存在
return i;
}
int search(vector<int>& nums, int target) {
if(nums.size() == 0) return 0;
int leftIndex = searchLeft(nums, target);
if(leftIndex == -1) return 0;
int rightIndex = searchRight(nums, target);
return rightIndex - leftIndex + 1;
}
};
可以将数组划分为两部分
左子数组:nums[i] = i;
右子数组:nums[i] != i;
缺失的数字等于“右子数组的首位元素”对应的索引。因此用binarySearch查找“右子数组的首位元素”
- 初始化:左边界 i = 0i=0 ,右边界 j = len(nums) - 1j=len(nums)−1 ;代表闭区间
[i, j][i,j]
。- 循环二分
m = i + (j -i) / 2
若nums[m] = m,则“右子数组的首位元素”一定是在[m + 1, j]中。则执行i = m + 1
若nums[m] != m,则“左子数组的末位元素”一定是在[i, m-1]中,则执行 j =m-1;- 返回值,跳出时, i > j,此时变量i和j分别指向“右子数组的首位元素”和“左子数组的末位元素”,此时返回i即可。
class Solution {
public:
int missingNumber(vector<int>& nums) {
int i = 0, j = nums.size() - 1;
while(i <= j){
int mid = (i + j) / 2; //向下取整
//跳出时,i和j分别指向“右子数组的首位元素”和
//“左子数组的末位元素”
if(nums[mid] == mid) i = mid + 1;
else{
j = mid - 1;
}
}
//跳出时, i > j
return i;
}
};
二叉树定义
struct TreeNode{
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x): val(x), left(NULL), right(NULL){}
};
给定一个字符串,请将字符串里的字符按照出现的频率降序排列,如果频率相同,则按照字符的ASCII码升序排列。
sort(vec.begin(), vec.end(), [](const pair<char, int> &x, const pair<char, int>& y)->int{
if(x.second == y.second)
return x.first < y.first;
else
return x.second > y.second;
});
滑动窗口模板
int left = 0, right = 0;
while (right < s.size()) {
// 增大窗口
window.add(s[right]);
right++;
while (window needs shrink) {
// 缩小窗口
window.remove(s[left]);
left++;
}
}