到处刷题,随便刷刷!我就不信我坚持不下来!
模板题,二分查找,时间复杂度O(logn)。y总模板yyds!
//模板一:左区间右端点
class Solution {
public:
int search(vector<int>& nums, int target) {
int l = 0, r = nums.size() - 1;
while(l < r)
{
int mid = l + r + 1>> 1;
if(nums[mid] <= target)//搞清楚check函数是什么?是左边区间的右端点,使得nums[mid]<=target
l = mid;
else r = mid - 1;
}
if(nums[l] == target)
return l;
else return -1;
}
};
//模板二:右区间左端点
class Solution {
public:
int search(vector<int>& nums, int target) {
int l = 0, r = nums.size() - 1;
while(l < r)
{
int mid = l + r >> 1;
if(nums[mid] >= target)
r = mid;
else l = mid + 1;
}
if(nums[l] == target)
return l;
else return -1;
}
};
yxc:二分的本质是找到区间的一个分界点,使得包含分界点的区间满足某个性质,不含分界点的区间不满足这个性质。两个模板:求左区间的右端点还是右区间的左端点。
easy
class Solution {
public:
int balancedStringSplit(string s) {
int n = s.size(), cnt = 0, R = 0, L = 0;
for(int i = 0; i < n; i++)
{
if(s[i] == 'L')
L++;
else R++;
if(L == R && L)
{
cnt++;
L = R = 0;
}
}
return cnt;
}
};
贪心 + 大顶堆
class Solution {
public:
struct ipo
{
int p, c;
bool operator<(const ipo& x)
{
if(c != x.c)
return c < x.c; //从小到大排序
else
return p < x.p;
}
};
int findMaximizedCapital(int k, int w, vector<int>& p, vector<int>& c) {
//每次选择满足启动资本的最大利润, 不断更新启动资本,直到超过k或者无法满足启动资本
//时间复杂度O(nlogn), 资本是不断增大的,i不断从当前位置向后,最多n
typedef pair<int, int> PII;
int n = p.size();
vector<PII> ipos(n);
for(int i = 0; i < n; i++)
ipos[i] = {c[i], p[i]};
sort(ipos.begin(), ipos.end()); //按照pair从小到大排序
priority_queue<int> q; //从大到小排
int i = 0;
while(k--)
{
while(i < n && w >= ipos[i].first)
q.push(ipos[i++].second);
if(q.size())
{
w += q.top();
q.pop();
}
}
return w;
}
};
class Solution {
public:
int chalkReplacer(vector<int>& chalk, int k) {
int n = chalk.size(), i = 0;
if(n == 1 && chalk[0] < k)
return 0;
long long sum = 0;
for(int i = 0; i < n; i++)
sum += chalk[i];
k = k % sum;
while(1)
{
if(k - chalk[i] < 0)
return i;
k = k - chalk[i++];
}
return i;
}
};
还可以最后一轮的时候,用前缀和二分。
class Solution {
public:
int chalkReplacer(vector<int>& chalk, int k) {
int n = chalk.size(), i = 0;
if(n == 1 && chalk[0] < k)
return 0;
vector<long long> sum(n + 1, 0);
for(int i = 1; i <= n; i++)
sum[i] = sum[i - 1] + chalk[i - 1];
k = k % sum[n];
int l = 1, r = n;
while(l < r)
{
int mid = l + r >> 1;
if(sum[mid] >= k)
r = mid;
else
l = mid + 1;
}
if(sum[l] == k)
return l;
else
return l - 1;
}
};
一开始绕进去了,想找连续1的,发现不好找。
就求不含连续1的,那么之前的二进制位也得是不含连续1的,当前位如果是1,下一位必须是0;当前位是0,下一位可以是1,可以是0;
有点编译原理自动机的意味了。
class Solution {
public:
int cnt = 1, max_n;
void dfs(int x)
{
if(x > max_n)
return;
cnt++;
if(x & 1)
dfs(x << 1);
else
{
dfs(x << 1);
dfs((x << 1) + 1);
}
}
int findIntegers(int n) {
max_n = n;
dfs(1);
return cnt;
}
};
没太看懂,继续理解
没想到贪心,自个儿在那一直dfs,超时剪枝超时呜呜呜
不过我发现我还不是最惨的,这个同学真可爱。
进入看了一眼
思路就是从大到小排序,然后求前cnt个和。如果是偶数直接返回即可;如果是奇数,那就从未选择的数和选择的数中选两个差值最小且奇偶性不同的即可,从cnt向两边找,找到第一组就返回就行。
如果最后发现sum还是奇数,就是没找到,返回0即可。
class Solution {
public:
int maxmiumScore(vector<int>& c, int cnt)
{
int n = c.size(), sum = 0;
sort(c.begin(), c.end(), greater<int>());
for(int i = 0; i < cnt; i++)
sum += c[i];
if(sum % 2 == 0) return sum;
for(int i = cnt; i < n; i++)//未选择的数
{
for(int j = cnt - 1; j >= 0; j--)//已选择的数
{
if((c[i] % 2) ^ (c[j] % 2)) //奇偶性相反
{
sum = sum - c[j] + c[i];
return sum;
}
}
}
if(sum % 2)
return 0;
return sum;
}
};
处理未匹配左括号的范围
class Solution {
public:
bool checkValidString(string s)
{
int mi = 0, ma = 0;//未匹配的左括号数量的最小值和最大值
for(int i = 0; i < s.size(); i++)
{
if(s[i] == '(') //左括号最大值和最小值都++
mi++, ma++;
else if(s[i] == '*')//*既可以匹配左括号最大值++,也可以匹配右括号最小值--
mi--, ma++;
else
mi--, ma--;//右括号匹配一个左括号,最小值最大值--
if(ma < 0)//说明括号多于左括号了
return false;
mi = max(0, mi); //最小值就是左括号 不可能小于0,小于0的情况就是把他当成右括号太多次而没有那么多左括号。
}
return mi == 0;//最小值为0表示左右括号匹配完毕
}
};
()* )( *
哈希表的运用
class Solution {
public:
int numberOfBoomerangs(vector<vector<int>>& p) {
int ans = 0, n = p.size(), cnt;
for(int i = 0; i < n; i++)
{
unordered_map<int, int> dist;
for(int j = 0; j < n; j++)
{
if(j == i) continue;
int dx = p[i][0] - p[j][0];
int dy = p[i][1] - p[j][1];
int d = dx * dx + dy * dy;
dist[d]++;
}
for(auto t : dist)
{
cnt = t.second;
ans += cnt * (cnt - 1);
}
}
return ans;
}
};
暴力一次就过了欸
bool cmp(const string& a, const string& b)
{
if(a.size() != b.size())
return a.size() > b.size();
else
return a < b;
}
class Solution {
public:
string findLongestWord(string s, vector<string>& d)
{
sort(d.begin(), d.end(), cmp);
//排序按照要求, 先返回长度长的,长度一样的选择字典序小的
int dn = d.size(), sn = s.size();
for(int i = 0; i < dn; i++)
{
string p = d[i];
int j = 0, k = 0, pn = p.size();
while(j < sn && k < pn)
{
if(s[j] == p[k])
j++, k++;
else
j++;
}
if(k == pn)
return p;
}
return "";
}
};
class Solution {
public:
int findPeakElement(vector<int>& nums) {
//nums.push_back(INT_MIN);
int l = 0, r = nums.size() - 1;
while(l < r)
{
int mid = (l + r) >> 1;
if(nums[mid] < nums[mid + 1])
l = mid + 1;
else
r = mid;
}
return l;
}
};
dfs搜索图中的单词
class Solution {
public:
vector<vector<char>> bo;
string wo;
int n, m;
int di[4] = {-1, 1, 0, 0};
int dj[4] = {0, 0, -1, 1};
bool dfs(int i, int j, int idx, vector<vector<bool>>& st)
{
if(idx == wo.size() - 1)
return wo[idx] == bo[i][j]; //得有个返回true的
if(wo[idx] != bo[i][j])
return false;
st[i][j] = true;
for(int k = 0; k < 4; k++)
{
int x = i + di[k], y = j + dj[k];
if(x < n && x >= 0 && y < m && y >= 0 && !st[x][y])
{
if(dfs(x, y, idx + 1, st))
return true;
}
}
st[i][j] = false;
return false;
}
bool exist(vector<vector<char>>& b, string w)
{
n = b.size(), m = b[0].size();
vector<vector<bool>> st(n, vector<bool>(m, false));
bo = b;
wo = w;
for(int i = 0; i < n; i++)
{
for(int j = 0; j < m; j++)
{
if(dfs(i, j, 0, st))
return true;
}
}
return false;
}
};
差最后一分钟打卡,已经一周了,昨天去吃了毛血旺和奶茶嘻嘻 !
dfs暴力搜索会在最后一个样例超时,做一些优化。
如果格子里有9个a,然后单词里有10个a,那显然是不可能的,可以提前终止。
class Solution {
public:
vector<vector<char>> bo;
string wo;
int n, m;
int di[4] = {-1, 1, 0, 0};
int dj[4] = {0, 0, -1, 1};
bool dfs(int i, int j, int idx, vector<vector<bool>>& st)
{
if(idx == wo.size() - 1)
return wo[idx] == bo[i][j];
if(wo[idx] != bo[i][j])
return false;
st[i][j] = true;
for(int k = 0; k < 4; k++)
{
int x = i + di[k], y = j + dj[k];
if(x < n && x >= 0 && y < m && y >= 0 && !st[x][y])
{
if(dfs(x, y, idx + 1, st))
return true;
}
}
st[i][j] = false;
return false;
}
vector<string> findWords(vector<vector<char>>& b, vector<string>& w)
{
n = b.size(), m = b[0].size();
bo = b;
vector<string> ans;
vector<int> cnt(26, 0);
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
cnt[b[i][j] - 'a']++;
for(int k = 0; k < w.size(); k++)
{
wo = w[k];
bool flag = false;
vector<int> cnt1(26, 0);
vector<vector<bool>> st(n, vector<bool>(m, false));
for(int p = 0; p < wo.size(); p++)
{
cnt1[wo[p] - 'a']++;
}
for(int p = 0; p < 26; p++)
if(cnt[p] < cnt1[p])
{
flag = true;
break;
}
for(int i = 0; i < n; i++)
{
if(flag) continue;
for(int j = 0; j < m; j++)
{
if(dfs(i, j, 0, st))
{
ans.push_back(wo);
flag = true;
break;
}
}
}
}
return ans;
}
};
Trie树 + dfs(哎!总是想不到…)
一次遍历数独, 使用哈希表判断是否存在冲突
class Solution {
public:
bool isValidSudoku(vector<vector<char>>& bo)
{
unordered_set<int> hashRow[9];
unordered_set<int> hashCol[9];
unordered_set<int> hashBox[9];
for(int i = 0; i < 9; i++)
{
for(int j = 0; j < 9; j++)
{
if(bo[i][j] == '.')
continue;
int x = bo[i][j] - '0';
int k = (i / 3) * 3 + j / 3;
auto tr = hashRow[i].find(x);
auto tc = hashCol[j].find(x);
auto tb = hashBox[k].find(x);
if(tr != hashRow[i].end() || tc != hashCol[j].end() || tb != hashBox[k].end())
return false;
else
{
hashRow[i].insert(x);
hashCol[j].insert(x);
hashBox[k].insert(x);
}
}
}
return true;
}
};
#include
using namespace std;
class Solution {
public:
unordered_set<int> hashRow[9];
unordered_set<int> hashCol[9];
unordered_set<int> hashBox[9];
bool dfs(int i, int j, vector<vector<char>>& b)
{
if(j == 9)
return dfs(i + 1, 0, b);
if(i == 9)
return true;
if(b[i][j] != '.')
return dfs(i, j + 1, b);
for(int n = 1; n <= 9; n++)
{
char x = n + '0';
int k = (i / 3) * 3 + j / 3;
auto tr = hashRow[i].find(n);
auto tc = hashCol[j].find(n);
auto tb = hashBox[k].find(n);
if(tr == hashRow[i].end() && tc == hashCol[j].end() && tb == hashBox[k].end())
{
hashRow[i].insert(n);
hashCol[j].insert(n);
hashBox[k].insert(n);
b[i][j] = x;
if(dfs(i, j + 1, b))
return true;
b[i][j] = '.';
hashRow[i].erase(n);
hashCol[j].erase(n);
hashBox[k].erase(n);
}
}
return false;
}
void solveSudoku(vector<vector<char>>& b)
{
for(int i = 0; i < 9; i++)
{
for(int j = 0; j < 9; j++)
{
if(b[i][j] != '.')
{
int x = b[i][j] - '0';
int k = (i / 3) * 3 + j / 3;
hashRow[i].insert(x);
hashCol[j].insert(x);
hashBox[k].insert(x);
}
}
}
dfs(0, 0, b);
}
};
同志们! 马上进入面试高峰期了 ! 最近可能会断写 ! 28号推免结束后见 ! 还有十天冲冲冲!
//9.29更新!辛苦没有白费,幸运给得太多了!去北大软微啦!接下来会继续刷题,沉淀技术,扎实基础,目标找个满意的实习嘻嘻!感谢所有帮助我的人!爱你们!
//放了个假, I’m back.
字符串哈希,如果在哈希表中个数是1,则加入;是0或者多于1个,都不加入。
class Solution {
public:
vector<string> findRepeatedDnaSequences(string s)
{
unordered_map<string, int> hashmap;
vector<string> ans;
string tmp;
if(s.size() <= 10)
return {};
for(int i = 0; i < 10; i++)
tmp += s[i];
hashmap.insert(make_pair(tmp, 1));
for(int i = 10; i < s.size(); i++)
{
tmp.erase(tmp.begin());
tmp += s[i];
if(hashmap[tmp] == 1)
ans.push_back(tmp);
hashmap[tmp]++;
}
return ans;
}
};
题目很好懂,模拟也可以,就是慢点
二分利用等差数列求和公式n = k * (k + 1) / 2
注意溢出,到处都可能溢出
二分查找找n枚硬币可以形成的完整的行数k
class Solution {
public:
int arrangeCoins(int n)
{
int l = 1, r = n;
while(l < r)
{
int mid = (long long) l + r + 1 >> 1;
if((long long)mid * (mid + 1) <= (long long) n * 2)
l = mid;
else
r = mid - 1;
}
return l;
}
};