记录朋友们与我遇到的手撕代码题和实战题。
读取数字。
int a;
float b;
scanf("%d %f", &a, &b);
//
cin >> a >> b;
读取带空格的字符串。
string s;
getline(cin, s);
读取直到换行符之前的值。
vector<int> v;
while (cin.peek() != '\n') {
int t;
cin >> t;
v.emplace_back(move(t));
}
输出printf或者cout
printf("outoput : %d.\n", a);
cout << a;
使用cin.peek()函数
while (cin.peek() != '\n') {
int tmp;
cin >> tmp;
nums.push_back(tmp);
}
cin.ignore();
或者这种方式也可以,但是我用vscode不好用。
while (1) {
int tmp;
cin >> tmp;
nums.push_back(tmp);
while (getchar() == '\n') break;
}
bool jump(vector<int>& nums) {
int n = nums.size();
int step = 0;
int maxP - 0; // 下一step能够到达最远的距离
int end = 0; // 每一step能够到达最远的距离
for (int i = 0; i < n; ++i) {
mP = min(n - 1, max(mP, i + nums[i]));
if (i == 0) end = mP;
else if (i == end) {
end = mP;
step++;
}
}
return step;
}
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(), nums.end());
int n = nums.size();
vector<vector<int>> ans;
for (int i = 0; i < n; ++i) {
while (i > 0 && i <= n - 2 && nums[i] == nums[i - 1]) i++;
auto result = twosum(nums, i + 1, n - 1, -nums[i]);
ans.insert(ans.end(), result.begin(), result.end());
}
return ans;
}
vector<vector<int>> twosum(vector<int>& nums, int start, int end, int target) {
vector<vector<int>> ans;
if (end <= start) return ans;
int sum = 0;
while (start < end) {
sum = nums[start] + nums[end];
if (sum == target) {
vector<int> tmp;
tmp.push_back(-target);
tmp.push_back(nums[start]);
tmp.push_back(nums[end]);
ans.push_back(tmp);
while (start < end && nums[start] == nums[start + 1]) start++;
start++;
while (start < end && nums[end] == nums[end - 1]) end--;
end--;
} else if (sum < target) start++;
else end--;
}
return ans;
}
int shipWithinDays(vector<int>& weights, int days) {
int n = weights.size(), r = 0, l = 0, m = 0;
for (int i = 0; i < n; ++i) {
r += weights[i];
l = max(l, weights[i]);
}
while (l <= r) {
m = (l + r) / 2;
int need = 1, cur = 0;
for (int w : weights) {
if (cur + w > m) {
need++;
cur = w;
} else cur += w;
}
if (need > days) l = m + 1;
else r = m - 1;
}
return l;
}
给出M条旅游线路,一行给出M个线路的起始日期,另一行给出M个线路的终止日期。输出有多少种满足有3条旅游地的方案。
比如4条线路,分别为:
5 1 3 2
7 2 4 4
输出为1,因为只有一条线路满足3个旅游地:
[1,2] - [3,4] - [5,7]
这一题是明显的回溯算法题,通过不断增加新的旅游地,判断是否满足各个旅游地起始终止日期不发生重叠。
原题是包含重复元素的实战题。我先从不含重复元素的开始整理。
void getans(vector<int>& nums, vector<vector<int>>& ans, const int len, int s1){
if (s1 == len) {
for (const int i: nums) cout << i << " ";
cout << endl;
ans.emplace_back(nums);
return;
}
for (int i = s1; i < len; ++i) {
swap(nums[i], nums[s1]);
getans(nums, ans, len, s1 + 1);
swap(nums[i], nums[s1]);
}
}
vector<vector<int>> permute(vector<int>& nums) {
int n = nums.size();
if (n == 1) return vector<vector<int>>{nums};
vector<vector<int>> ans;
getans(nums, ans, n, 0);
return ans;
}
如果是含重复元素的全排列问题,在排序后应该会处于相邻的位置,此时只需要判断相邻是否一样即可。
void getans(vector<int>& nums, vector<vector<int>>& ans, const int len, int s1){
if (s1 == len) {
for (const int i: nums) cout << i << " ";
cout << endl;
ans.emplace_back(nums);
return;
}
set<int> s;
for (int i = s1; i < len; ++i) {
if (i > s1 && nums[s1] == nums[i]) continue; // 避免相邻的相同
if (s.find(nums[i]) != s.end()) continue; // 避免待交换的相同
s.insert(nums[i]); // 避免以后出现相同的
swap(nums[s1], nums[i]);
getans(nums, ans, len, s1 + 1);
swap(nums[s1], nums[i]);
}
}
我在集度面试的时候也遇到了,而且额外要求输出是字典序,所以需要再sort一遍。现整理如下。
class Solution {
private:
vector<vector<int> > ans;
public:
vector<vector<int> > permuteUnique(vector<int> &num) {
sort(num.begin(), num.end());
int n = num.size();
backtracking(num, 0, n);
sort(ans.begin(), ans.end());
return ans;
}
void backtracking(vector<int> &num, int idx, int n) {
if (idx == n - 1) {
ans.push_back(num);
return;
}
backtracking(num, idx + 1, n);
set<int> s;
for (int i = idx; i < n; ++i) {
if (num[idx] == num[i]) continue;
if (s.find(num[i]) != s.end()) continue;
s.insert(num[i]);
swap(num[idx], num[i]);
backtracking(num, idx + 1, n);
swap(num[idx], num[i]);
}
}
};
void bisection(vector<int> nums, int target) {
int l = 0, r = nums.size() - 1, mid = 0;
while (l <= r) {
mid = (l + r) / 2;
if (nums[mid] >= target) r = mid - 1;
else l = mid + 1;
}
cout << r << endl;
}
ListNode* removeDuplicateNodes(ListNode* head) {
set<int> s;
if (!head || !head->next) return head;
ListNode* prev = head, *cur = head->next;
s.insert(head->val);
while (cur) {
if (s.find(cur->val) != s.end()) {
prev->next = cur->next;
cur = cur->next;
continue;
}
s.insert(cur->val);
prev = cur;
cur = cur->next;
}
return head;
}
#include
#include
using namespace std;
int main() {
string s = "dddbccbad";
int n = s.size(), l = 0, len = 0;
vector<vector<bool>> dp(n, vector<bool>(n, false));
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n - i; ++j) {
if (i == 0) dp[j][j] = true;
else {
if (s[i + j] == s[j] && (i == 1 || dp[j + 1][i + j - 1])) {
dp[j][i + j] = true;
if (i > len) {
l = j;
len = i + 1;
}
}
}
}
}
cout << s.substr(l, len);
return 0;
}
#define swap(x, y) do{x=x+y;y=x-y;x=x-y;}while(0)
这是朋友面试遇到的题目,是leetcode第76题,属于hard,特此记录一下。
string minWindow(string s, string t) {
// count用来记录位数,之后遍历的时候遇到一个而且需要的话就减一个
// l r 双指针
// minl minlen 记录最短的下标起始和长度
// 注意minlen初始化长度为一个很大的值,是因为有可能没有满足要求的子串,通过这个较大值来判断是否有
int count = t.size(), l = 0, r = 0, minl = 0, minlen = s.size() + 1;
vector<bool> exist(128, false); // 用来记录t中某个字母存不存在,也可以用哈希表来找
vector<int> need(128, 0); // 用来记录t中字母出现的次数,因为可能重复
for (char c : t) {
need[t]++;
exist[t] = true;
}
for (;r < s.size(); ++r) { // 开始双指针遍历
if (exist[s[r]]) {
if (need[s[r]] > 0) count--; // 找到一个需要的字母
need[s[r]]--; // 不管需不需要,都提供了
while (count == 0) {
if (minlen > r - l + 1) { // 更新最短字符串
minl = l;
minlen = r - l + 1;
}
// 开始移动左指针
if (exist[s[l]]) need[s[l]]++; // 提供的少了1个
if (need[s[l]] > 0) count++; // 如果把l对应的字母拿掉,count就得+1个
l++;
}
}
}
if (minlen == s.size() + 1) return ""; // 每找到,返回空字符串
return s.substr(minl, minlen);
}
两数之和的升级版。
vector<vector<int>> threeSum(vector<int>& nums) {
int n = nums.size();
vector<vector<int>> ans;
if (n < 3) return ans;
for (int i = 0; i < n - 2; ++i) { // 固定住第1位
if (i > 0 && nums[i] == nums[i - 1]) continue;
int target = -nums[i], r = n - 1;
for (int l = i + 1; l < n - 1; ++l) { // 固定住第2位
if (l > i + 1 && nums[l] == nums[l - 1]) continue;
while (l < r && nums[l] + nums[r] > target) r--; // 因为第2位固定住了,所以只能移动第3位
if (l == r) continue; // 有可能r退到l处了
if (nums[l] + nums[r] == target) ans.push_back({nums[i], nums[l], nums[r]});
}
}
return ans;
}
Leetcode第11题。思想是双指针,总是移动矮的那根。
int maxArea(vector<int>& height) {
int n = height.size(), l = 0, r = n - 1, ans = (n - 1) * min(height[l], height[r]);
while (l < r) {
ans = height[l] < height[r] ?
max(ans, min(height[++l], height[r]) * (r - l)) : max(ans, min(height[l], height[--r]) * (r - l));
}
return ans;
}
封装,继承,多态。
封装,继承,多态。
move将一个左值强行转化为右值,通过右值引用使用该值,可以避免拷贝,提高效率。
常见应用场景:
1.移动构造函数
2.vector.emplace_back()
堆内存由程序员创建和释放,栈内存由编译器自动创建和释放。
堆频繁使用会产生大量碎片,使程序效率降低;栈由于是编译器管理则不会产生这个问题。
栈的内存地址向减小方向使用;堆的内存地址向增大方向使用。
函数调用层数过多,每调用一次,函数的参数、局部变量等信息就压一次栈;
局部静态变量体积过大。
一是增大栈空间;二是改用动态分配,使用堆(heap)而不是栈(stack)。