/*******************************************************************************
避免洪水泛滥
//leetcode-cn.com/problems/avoid-flood-in-the-city/solution/avoid-flood-in-the-city-by-ikaruga/
rains : 1 0 2 0 2 1
*******************************************************************************/
class Solution {
public:
vector<int> avoidFlood(vector<int> &rains) {
vector<int> ans(rains.size(), 1);
unordered_map<int, int> water; //记录每个湖泊上一次下雨的日期
set<int> zero;
for (int i = 0; i < rains.size(); i++) {
int r = rains[i];
if (r == 0) {
//将晴天的日期记录到zero中,遇到晴天时,先不用管抽哪个湖
zero.insert(i);
continue;
}
if (water.count(r) != 0) { //当下雨时,湖泊已经水满时,可以查询上次下雨的日期
auto it = zero.lower_bound(water[r]); //通过上次下雨的日期,查找对应的晴天日期
if (it == zero.end()) { //如果没有找到,则无法使用那天抽水,发生洪水
return {};
}
ans[*it] = r; // 如果在晴天*it找到了对应的下雨日期,则记录抽干的湖泊
zero.erase(it); //删除当前的晴天记录
}
// water记录每个湖泊上一次下雨的日期
water[r] = i; //更新当前湖的下雨日期
ans[i] = -1;
}
return ans;
}
};
/*******************************************************************************
并查集
*******************************************************************************/
void join(int p, int q){
int rootP = find(p);
int rootQ = find(q);
if(rootP == rootQ){
return;
}
//将两棵树合并为一棵
parent[rootP] = rootQ;
return;
}
int find(int p){
while(p != parent[p]){ //如果P的父亲指针指向不是自己,说明P不是根元素
//在find查询中嵌入一个路径压缩 此处不懂,参考这里https://blog.csdn.net/qq_19782019/article/details/78919990
parent[p] = parent[parent[p]];
//p元素不再选择原来的父亲节点,而是选择父亲节点的父亲节点作为自己的新的一个父亲节点
p = parent[p];
}
//经过while循环后,p = parent[p], 一定是一个根节点,且不能够再进行压缩
return p;
}
/*******************************************************************************
1319. 连通网络的操作次数
//leetcode-cn.com/problems/number-of-operations-to-make-network-connected/
两种方法:并查集 和 深度优先探索
*******************************************************************************/
/*并查集*/
class Solution {
public:
int* parent;
int find(int p){
while(p != parent[p]){
parent[p] = parent[parent[p]];
p = parent[p];
}
return p;
}
void join(int x, int y){
int rootX = find(x);
int rootY = find(y);
if(rootX == rootY){
return;
}
parent[rootX] = rootY;
return;
}
int makeConnected(int n, vector<vector<int>>& connections) {
if(connections.size()<n-1) //不满足线缆数量
return -1;
parent = new int[n]; //申请n个空间
for(int i =0;i<n;i++){
parent[i] = i; //初始化
}
for(int i =0;i<connections.size();i++){
join(connections[i][0],connections[i][1]); //连接
}
set<int> pars;
for(int i =0;i<n;i++){ //计算连通分量数
pars.insert(find(i)); //每个节点的根节点插入pars,每个键都是唯一的,可以插入或删除但不能更改
}
return pars.size()-1;
}
};
class Solution {
private:
vector<int> fa;
public:
int find(int x){
return x == fa[x] ? x : fa[x] = find(fa[x]); // 这种是未压缩路径
// return x == fa[x] ? x : x = find(fa[x]);
}
int makeConnected(int n, vector<vector<int>>& connections){
if(connections.size() < n-1){
return -1;
}
fa.resize(n); //初始化
iota(fa.begin(), fa.end(), 0);
int part = n; //初始化共有n个连通分量数
for(auto&& c : connections){ //连接
int p = find(c[0]), q = find(c[1]);
if(p != q){
--part;
fa[p] = q;
}
}
return part - 1;
}
};
/*
邻接矩阵深度优先探索算法
*/
class Solution{
private:
vector<vector<int>> edges;
vector<bool> used;
public:
void dfs(int u){
used[u] = true; //将已访问的定点标记true
for(int v : edges[u]){ //对于顶点u的其他相邻的节点,进行继续深度优先探索
if(!used[v]){
dfs(v);
}
}
}
int makeConnected(int n, vector<vector<int>> & connections){
if(connections.size() < n-1){
return -1;
}
edges.resize(n);
for(auto&& c: connections){ //组合无向图
edges[c[0]].push_back(c[1]);
edges[c[1]].push_back(c[0]);
}
used.resize(n);
int part = 0;
for(int i = 0; i < n; i++){ //遍历所有顶点,计算连通数量
if(!used[i]){
++part;
dfs(i);
}
}
return part-1;
}
};
/*邻接矩阵的广度优先探索*/
class Solution {
public:
int makeConnected(int n, vector<vector<int>>& connections) {
if (connections.size() < (n-1)) {
return -1;
}
//将相连接的组合成一个无向图
unordered_map<int, unordered_set<int>> link_map;
for (auto &conn : connections) {
link_map[conn[0]].emplace(conn[1]);
link_map[conn[1]].emplace(conn[0]);
}
vector<int> mark(n, 0);
int num = 0;
for (int i = 0; i < n; ++i) {
if (mark[i]) continue;
num++;
queue<int> q;
q.push(i);
while (!q.empty()) {
int index = q.front();
q.pop();
if (link_map.count(index) == 0) {
continue;
}
for (auto mi : link_map[index]) {
if (mark[mi]) continue;
q.push(mi);
mark[mi] = 1;
}
}
}
return num-1;
}
};
/*******************************************************************************
邻接矩阵:深度优先遍历,广度优先遍历
深度优先遍历:不断地沿着顶点的深度方向遍历;顶点的深度方向:它的邻接点方向。
用visited[i]表示顶点i的访问情况。
广度优先遍历:先访问当前顶点的所有邻接点;先访问顶点的邻接点先于后访问顶点的邻接点被访问
*******************************************************************************/
//访问标志数组
int visited[MAX] = {0};
void DFS(M G, int v){
visited[v] = 1;
}
/*******************************************************************************
朋友圈
//leetcode-cn.com/problems/friend-circles/
*******************************************************************************/
class Solution {
public:
vector<int> fa;
int find(int p){
while(p != fa[p]){
fa[p] = fa[fa[p]];
p = fa[p];
}
return p;
}
void Union(int p, int q){
int rootP = find(p);
int rootQ = find(q);
if(rootP != rootQ){
fa[rootP] = rootQ;
}
return;
}
int findCircleNum(vector<vector<int>>& M) {
int n = M.size();
fa.resize(n); //申请n个空间
for(int i = 0; i < n; i++){ //初始化
fa[i] = i;
}
//连接
for(int i=0;i<n;++i){
for(int j=0;j<n;++j){
if(M[i][j]==1 && i!=j)
Union(fa[i], fa[j]);
}
}
//计算有多少个连通分量数
int count = 0;
for(int i = 0; i < n; i++){
if(fa[i] == i){
++count;
}
}
return count;
//计算有多少个连通分量数
// set<int> pars;
// for(int i =0;i<n;i++){
// pars.insert(find(i)); //每个节点的根节点插入pars,每个键都是唯一的,可以插入或删除但不能更改
// }
// return pars.size();
}
};
/*深度优先探索*/
//把矩阵 M 看成是图的邻接矩阵,则问题转化为求图的连通块数
class Solution {
private:
vector<bool> vis;
public:
int findCircleNum(vector<vector<int>>& M){
int n = M.size();
vis.resize(n);
int ans = 0;
for(int i = 0; i < n; i++){
if(vis[i] == false){
dfs(M, i);
ans++;
}
}
return ans;
}
void dfs(vector<vector<int>> M, int i){
int n = M.size();
for(int j = 0; j < n; j++){
if(M[i][j] == 1 && vis[j] == false){
vis[j] = true;
dfs(M, j);
}
}
}
};
/*广度优先探索*/
class Solution {
public:
int findCircleNum(vector<vector<int>>& M){
int n = M.size();
vector<int> visit(n, 0);
int count = 0, tmp;
queue<int> que;
for(int i = 0; i < n; i++){
if(!visit[i]){
count++;
que.push(i);
while(!que.empty()){
tmp = que.front();
que.pop();
visit[tmp] = 1;
for(int j = 0; j < n; j++){
if(M[tmp][j] == 1 && !visit[j]){
que.push(j);
}
}
}
}
}
return count;
}
};
/*******************************************************************************
820. 单词的压缩编码
//leetcode-cn.com/problems/short-encoding-of-words/
*******************************************************************************/
class Solution {
public:
int minimumLengthEncoding(vector<string>& words) {
//unordered_set<string> good(words.begin(), words.end());
unordered_set<string> origin;
for(auto& word : words){
origin.insert(word);
}
for (const string& word: words) {
for (int k = 1; k < word.size(); ++k) {
origin.erase(word.substr(k));
}
}
int ans = 0;
for (const string& word: origin) {
ans += word.size() + 1;
}
return ans;
}
};
/*******************************************************************************
LCP 08. 剧情触发时间
//leetcode-cn.com/problems/ju-qing-hong-fa-shi-jian/
*******************************************************************************/
#define col 3
class Solution {
public:
vector<int> getTriggerTime(vector<vector<int>>& increase, vector<vector<int>>& requirements) {
vector<int> res;
int row = increase.size();
cout << row << endl;
vector<vector<int>> sum(row+1, vector<int>(col,0));
for(int i = 0; i < row; i++){
for(int j = 0; j < col; j++){
sum[i+1][j] = sum[i][j] + increase[i][j];
}
}
for(auto v : requirements){
int l = 0, r = row;
while(l < r){
int m = (l + r) / 2;
if(sum[m][0] >= v[0] && sum[m][1] >= v[1] && sum[m][2] >= v[2]){
r = m;
} else {
l = m + 1;
}
}
if(sum[l][0] >= v[0] && sum[l][1] >= v[1] && sum[l][2] >= v[2]){
res.push_back(l);
} else {
res.push_back(-1);
}
}
return res;
}
};
class Solution{
public:
vector<int> getTriggerTime(vector<vector<int>>& increase, vectoro<vector<int>>& requirements){
vector<int> C(increase.size()+1, 0);
vector<int> R(increase.size()+1, 0);
vector<int> H(increase.size()+1, 0);
for(int i = 0; i < inrease.size(); ++i){
C[i+1] = C[i] + increase[i][0];
R[i+1] = R[i] + increase[i][1];
H[i+1] = H[i] + increase[i][2];
}
vector<int> res;
int maxLen = C.size();
for(int i = 0; i < requirements.size(); i++){
int lc = lower_bound(C.begin(), C.end(), requirements[i][0]) - C.begin();
int lr = lower_bound(R.begin(), R.end(), requirements[i][1]) - R.begin();
int lh = lower_bound(H.begin(), H.end(), requirements[i][2]) - H.begin();
if(lc == maxLen || lr == maxLen || lh == maxLen){
res.push_back(-1);
} else {
res.push_back(max(max(lc,lr),lh));
}
}
return res;
}
};
/*******************************************************************************
76. 最小覆盖子串
//leetcode-cn.com/problems/minimum-window-substring/
*******************************************************************************/
class Solution {
public:
string minWindow(string s, string t) {
unordered_map<char, int> need;
unordered_map<char, int> windows;
int len = s.size() + 1;
int start = 0;
//先计算need
for(auto w : t){
++need[w];
}
int left = 0, right = 0, valid = 0; //初始化
while(right < s.size()){
char chr = s[right];
++right;
if(need.count(chr)){
++windows[chr];
if(windows[chr] == need[chr]){
valid++;
}
}
while(valid == need.size()){
if(right - left < len){
start = left;
len = right - left;
}
char chl = s[left];
++left;
if(need.count(chl)){
if(windows[chl] == need[chl]){
--valid;
}
--windows[chl];
}
}
}
return len == s.size()+1 ? "" : s.substr(start, len);
}
};
/*******************************************************************************
438. 找到字符串中所有字母异位词
//leetcode-cn.com/problems/find-all-anagrams-in-a-string/
*******************************************************************************/
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
unordered_map<char, int> window;
unordered_map<char, int> need;
for(auto c : p){
need[c]++;
}
int left = 0, right = 0, valid = 0;
vector<int> res;
while(right < s.size()){
char c = s[right];
right++;
if(need.count(c)){
window[c]++;
if(window[c] == need[c]){
valid++;
}
}
//判断左侧端口是否要收缩
while(right - left >= p.size()){
if(valid == need.size()){
res.push_back(left);
}
char d = s[left];
left++;
if(need.count(d)){
if(window[d] == need[d]){
valid--;
}
window[d]--;
}
}
}
return res;
}
};
/*******************************************************************************
567. 字符串的排列
//leetcode-cn.com/problems/permutation-in-string/
*******************************************************************************/
class Solution {
public:
bool checkInclusion(string s1, string s2) {
unordered_map<char, int> need, window;
for(auto c : s1){
need[c]++;
}
int left = 0, right = 0;
int valid = 0;
while(right < s2.size()){
char c = s2[right];
right++;
if(need.count(c)){
window[c]++;
if(window[c] == need[c]){
valid++;
}
}
while(right - left >= s1.size()){
if(valid == need.size()){
return true;
}
char d = s2[left];
left++;
if(need.count(d)){
if(window[d] == need[d]){
valid--;
}
window[d]--;
}
}
}
return false;
}
};
/*******************************************************************************
3. 无重复字符的最长子串
//leetcode-cn.com/problems/longest-substring-without-repeating-characters/
*******************************************************************************/
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_map<char, int> window;
int left = 0, right = 0;
int res = 0;
while(right < s.size()){
char c = s[right];
right++;
//进行窗口数据更新
window[c]++;
//判断窗口是否要收缩
while(window[c] > 1){
char d = s[left];
left++;
window[d]--;
}
res = max(res, right-left);
}
return res;
}
};
/*******************************************************************************
II. 左旋转字符串
//leetcode-cn.com/problems/zuo-xuan-zhuan-zi-fu-chuan-lcof/
*******************************************************************************/
class Solution {
public:
string reverseLeftWords(string s, int n) {
reverse(s.begin(), s.begin()+n);
reverse(s.begin()+n, s.end());
reverse(s.begin(), s.end());
return s;
}
};
/*******************************************************************************
N皇后
//leetcode-cn.com/problems/n-queens/
*******************************************************************************/
class Solution {
public:
vector<vector<string>> res;
vector<vector<string>> solveNQueens(int n) {
vector<string> board(n, string(n, '.'));
backtrack(board, 0);
return res;
}
void backtrack(vector<string>& board, int row){
//触发条件
if(row == board.size()){
res.push_back(board);
return;
}
int n = board[row].size();
for(int col = 0; col < n; col++){
if(!isValid(board ,row, col)){
continue;
}
//做选择
board[row][col] = 'Q';
// 进行下一步策略
backtrack(board, row+1);
//撤回选择
board[row][col] = '.';
}
}
bool isValid(vector<string>& board, int row, int col){
int n = board.size();
//检查列是否有皇后冲突
for(int i = 0; i < n; i++){
if(board[i][col] == 'Q'){
return false;
}
}
//检查右上方是否有皇后互相冲突
for(int i = row-1, j = col + 1; i>=0 && j < n; i--, j++){
if(board[i][j] == 'Q'){
return false;
}
}
//检查左上方是否有皇后互相冲突
for(int i = row-1, j = col - 1; i>=0 && j >= 0; i--, j--){
if(board[i][j] == 'Q'){
return false;
}
}
return true;
}
};
/*******************************************************************************
980. 不同路径 III
//leetcode-cn.com/problems/unique-paths-iii/
*******************************************************************************/
class Solution {
public:
int uniquePathsIII(vector<vector<int>>& grid) {
int startX = 0, startY = 0, stepNum = 1;
//遍历获取起始位置和统计总步数
for(int i = 0; i < grid.size(); i++){
for(int j = 0; j < grid[0].size(); j++){
if(grid[i][j] == 1){
startX = j;
startY = i;
continue;
}
if(grid[i][j] == 0){
stepNum++;
}
}
}
return dfs(startX, startY, stepNum, grid);
}
int dfs(int x, int y, int stepSur, vector<vector<int>>& grid){
if(x < 0 || x >= grid[0].size() || y < 0 || y >= grid.size() || grid[y][x] == -1){
return 0;
}
if (grid[y][x] == 2) return stepSur == 0 ? 1 : 0;
grid[y][x] = -1;
int res = 0;
res += dfs(x-1, y, stepSur -1 ,grid);
res += dfs(x + 1, y, stepSur - 1, grid);
res += dfs(x, y - 1, stepSur - 1, grid);
res += dfs(x, y + 1, stepSur - 1, grid);
grid[y][x] = 0;
return res;
}
};
/*******************************************************************************
833. 字符串中的查找与替换
//leetcode-cn.com/problems/find-and-replace-in-string/
*******************************************************************************/
class Solution {
public:
string findReplaceString(string S, vector<int>& indexes, vector<string>& sources, vector<string>& targets) {
int n = S.size();
vector<string> vec(n, "");
string res = "";
for (int i = 0; i < S.size(); ++i) vec[i] += S[i];
for (int i = 0; i < indexes.size(); ++i) {
int size = sources[i].size();
if (S.substr(indexes[i], size) == sources[i]) {
vec[indexes[i]] = targets[i];
for (int j = indexes[i] + 1; j < indexes[i] + size; ++j)
vec[j] = "";
}
}
for (auto str : vec) {
res += str;
}
return res;
}
};
/*******************************************************************************
84. 柱状图中最大的矩形
//leetcode-cn.com/problems/largest-rectangle-in-histogram/
*******************************************************************************/
class Solution {
public:
int largestRectangleArea(vector<int>& heights)
{
int ans = 0;
vector<int> st;
heights.insert(heights.begin(), 0);
heights.push_back(0);
for (int i = 0; i < heights.size(); i++)
{
while (!st.empty() && heights[st.back()] > heights[i])
{
int cur = st.back();
st.pop_back();
int left = st.back() + 1;
int right = i - 1;
ans = max(ans, (right - left + 1) * heights[cur]);
}
st.push_back(i);
}
return ans;
}
};
class Solution {
public:
int largestRectangleArea(vector<int>& heights){
int res = 0;
stack<int> tack;
heights.insert(heights.begin(), 0);
heights.push_back(0);
for(int i = 0; i < heights.size(); i++){
while(!tack.empty() && heights[tack.top()] > heights[i]){
int cur = tack.top();
tack.pop();
int left = tack.top() + 1;
int right = i - 1;
//heights[cur] 是 离heights[i] 最远的那个且大于heights[i],right-left 是递增的宽度
res = max(res, (right - left + 1) * heights[cur]);
}
tack.push(i);
}
return res;
}
};
/*******************************************************************************
735. 行星碰撞
//leetcode-cn.com/problems/asteroid-collision/
*******************************************************************************/
class Solution {
public:
vector<int> asteroidCollision(vector<int>& asteroids) {
vector<int> res;
for(auto v : asteroids){
bool flag = true;
while(!res.empty() && v < 0 && res.back() > 0){
int sum = res.back() + v;
if(sum <= 0){
res.pop_back();
}
if(sum >= 0) {
flag = false;
break;
}
}
if(flag){
res.push_back(v);
}
}
return res;
}
};
/*******************************************************************************
2. 两数相加
//leetcode-cn.com/problems/add-two-numbers/
*******************************************************************************/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode* head = nullptr;
ListNode* tail = nullptr;
int carry = 0;
if(l1 == nullptr){
return l2;
}
if(l2 == nullptr){
return l1;
}
while(l1 || l2){
int n1 = l1 ? l1->val : 0;
int n2 = l2 ? l2->val : 0;
int sum = n1 + n2 + carry;
if(!head){
head = tail = new ListNode(sum % 10);
} else {
tail->next = new ListNode(sum % 10);
tail = tail->next;
}
carry = sum / 10;
if(l1){
l1 = l1->next;
}
if(l2){
l2 = l2->next;
}
}
if(carry > 0){
tail->next = new ListNode(carry);
}
return head;
}
};
/*******************************************************************************
15. 三数之和---左右指针
//leetcode-cn.com/problems/3sum/
*******************************************************************************/
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
sort(nums.begin(), nums.end());
int target;
for(int i = 0; i < nums.size(); i++){
if(i > 0 && nums[i] == nums[i-1]){
continue;
}
if((target = nums[i]) > 0){
break;
}
int l = i + 1;
int r = nums.size()-1;
while(l < r){
if(nums[l] + target + nums[r] < 0){
++l;
} else if(nums[l] + target + nums[r] > 0){
--r;
} else {
res.push_back({nums[l], target, nums[r]});
++l;
--r;
while(l < r && nums[l] == nums[l-1]){
l++;
}
while(l < r && nums[r] == nums[r+1]){
r--;
}
}
}
}
return res;
}
};
/*******************************************************************************
面试题 08.12. 八皇后---回溯法
//leetcode-cn.com/problems/eight-queens-lcci/
*******************************************************************************/
class Solution1 {
public:
vector<vector<string>> res;
vector<vector<string>> solveNQueens(int n) {
vector<string> board(n, string(n, '.'));
backtrack(board ,0);
return res;
}
void backtrack(vector<string>& board, int row){
if(row == board.size()){
res.push_back(board);
return;
}
int n = board[row].size();
for(int col = 0; col < n; col++){
if(!isValid(board, row, col)){
continue;
}
board[row][col] = 'Q';
backtrack(board, row+1);
board[row][col] = '.';
}
}
bool isValid(vector<string>& board, int row, int col){
int n = board.size();
//检查列是否有冲突
for(int i = 0; i < n; i++){
if(board[i][col] == 'Q'){
return false;
}
}
//检查右上方对角线
for(int i = row-1, j= col+1; i >= 0 && j < n; i--, j++){
if(board[i][j] == 'Q'){
return false;
}
}
//检查左上方对角线
for(int i = row-1, j = col-1; i >= 0 && j >= 0; i--, j--){
if(board[i][j] == 'Q'){
return false;
}
}
return true;
}
};
/*******************************************************************************
980. 不同路径 III---回溯法
//leetcode-cn.com/problems/unique-paths-iii/
*******************************************************************************/
class Solution3{
public:
int uniquePathsIII(vector<vector<int>>& grid){
int res = 0;
int startX = 0, startY = 0;
int step = 0;
for(int i = 0; i < grid.size(); i++){
for(int j = 0; j < grid[0].size(); j++){
if(grid[i][j] == 1){
startX = i;
startY = j;
continue;
}
if(grid[i][j] == 0){
step++;
}
}
}
//step + 1 针对step != 0 时,则直接返回res = 0
trackBack(grid, startX, startY, step+1, res);
return res;
}
void trackBack(vector<vector<int>>& grid, int startX, int startY, int step, int &res){
if(startX < 0 || startX >= grid.size() || startY < 0 || startY >= grid[startX].size() || grid[startX][startY] == -1){
return;
}
if(grid[startX][startY] == 2){
if(step == 0){
res++;
}
return;
}
grid[startX][startY] = -1;
trackBack(grid, startX-1, startY, step-1, res);
trackBack(grid, startX+1, startY, step-1, res);
trackBack(grid, startX, startY-1, step-1, res);
trackBack(grid, startX, startY+1, step-1, res);
grid[startX][startY] = 0;
}
};