INT_MAX
给到一个目标值和 一个数组 返回数组中两数相加和等于目标值
方法1 暴力循环 两个for
方法2
建立哈希表 map
map中存放 键值对 键为 数 , 值为num【i】的位置i
然后一个个放入 num的数 ,一边放 一边查是否有,插入之前先找,防止找到的人是自己。
map.find为查找是否存在键
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> hashtable;
for (int i = 0; i < nums.size(); ++i) {
auto it = hashtable.find(target - nums[i]);
if (it != hashtable.end()) {
return {it->second, i};
}
hashtable[nums[i]] = i;
}
return {};
}
};
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/two-sum/solution/liang-shu-zhi-he-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
1 注意用指针接受由new创建的对象 直接就是地址
2 ListNode *head = nullptr, *tail = nullptr;
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode *head = nullptr, *tail = nullptr;
int carry = 0;
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;
}
};
哈希集合 有点像set
滑动窗口思想
set从左边开始 不断往右边增加
左指针从0开始 然后右指针不断向右靠,同时判断右边的这个字符在set里有没有,没得话就加入,有的话就退出.
不断删set第一个字符,左指针不断加1
class Solution {
public:
int lengthOfLongestSubstring(string s) {
// 哈希集合,记录每个字符是否出现过
unordered_set<char> occ;
int n = s.size();
// 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
int rk = -1, ans = 0;
// 枚举左指针的位置,初始值隐性地表示为 -1
for (int i = 0; i < n; ++i) {
if (i != 0) {
// 左指针向右移动一格,移除一个字符
occ.erase(s[i - 1]);
}
while (rk + 1 < n && !occ.count(s[rk + 1])) {
// 不断地移动右指针
occ.insert(s[rk + 1]);
++rk;
}
// 第 i 到 rk 个字符是一个极长的无重复字符子串
ans = max(ans, rk - i + 1);
}
return ans;
}
};
int lengthOfLongestSubstring(string s) {
if(s.length()==1)
return 1;
int left=0, right = 0;
int max1=0;
int num = 0;
unordered_set<char> set1;
for(int i = 0; i<s.length(); i++)
{
while(!set1.insert(s[i]).second)
{
//max1 = max(max1,right-left+1);
set1.erase(s[left]);
left++;
}
max1 = max(max1,right-left+1);
right++;
//max1 = max(max1,right-left+1);
}
return max1;
}
整数除法都是向下取整
所以不管偶数奇数
(m+n+1)/2 结果都是一样的
较短数组 在左边或者右边 没有元素
此时需要在较短数组确定位置 那么较长数组两边确定有位置。
当两个数组长度相同,那么有可能 两个都是 各占一边
为了防止访问数组下标越界, 将数量较少的 放在前面
total left = (m+n+1)/2
等价于 m+ (n-m+1)/2
二分查找思路为 不断分割确认 分割元素在左边还是右边
i的下标在中间位置 相当于 (a+b)/2
注意当左边界为i 并且 区间只有两个元素时, 会陷入死循环,因为他会不断判断
nums1[i-1] <= nums[j] 成立,然后 把i给left, 此时left小于right 进入循环
新的i成为 left +二分之一 仍旧是 left 搜索区间仍旧是 原来的两个元素的。
加上二分之一就会使left大于等于 right 从而跳出循环
同时由于加1 不会使 i取到0下标,从而0-1不会越界产生-1
同时这里考虑数组下标越界的情况
如果i 取到 0 就意味着 整个数组在右边 那么左边给一个象征意义上的最小值,保证不会被取到 因为取左边界两个数字中较大的
如果i为m 就是整个在左边,右边给一个象征意义最大值 取左边两个数字中最小的
j也是同理
string longestPalindrome(string s)
{
if (s.length() < 1)
{
return "";
}
int start = 0, end = 0;
for (int i = 0; i < s.length(); i++)
{
int len1 = expandAroundCenter(s, i, i);//一个元素为中心
int len2 = expandAroundCenter(s, i, i + 1);//两个元素为中心
int len = max(len1, len2);
if (len > end - start)
{
start = i - (len - 1) / 2;
end = i + len / 2;
}
}
return s.substr(start, end - start + 1);
}
int expandAroundCenter(string s, int left, int right)
{
int L = left, R = right;
while (L >= 0 && R < s.length() && s[L] == s[R])
{// 计算以left和right为中心的回文串长度
L--;
R++;
}
return R - L - 1; 注意 他这里 由于 R和L 都加了1 实际长度没那么长 所以减去了
}
class Solution {
public:
string convert(string s, int numRows) {
if (numRows == 1) return s;
vector<string> rows(numRows);
// 行转向标志,极妙
int flag = 1;
// 行下标索引
int idxRows = 0;
for (int i = 0; i < s.size(); i++) {
rows[idxRows].push_back(s[i]);
// 更新行下标
idxRows += flag;
if (idxRows == numRows - 1 || idxRows == 0) {
// 转向,上——>下 | 下——>上
flag = -flag;
}
}
string res;
for (auto row : rows) {
// 拿到答案
res += row;
}
return res;
}
};
class Solution {
public:
string convert(string s, int numRows) {
if (numRows == 1) return s;
vector<string> rows(min(numRows, int(s.size()))); // 防止s的长度小于行数
int curRow = 0;
bool goingDown = false;
for (char c : s) {
rows[curRow] += c;
if (curRow == 0 || curRow == numRows - 1) {// 当前行curRow为0或numRows -1时,箭头发生反向转折
goingDown = !goingDown;
}
curRow += goingDown ? 1 : -1;
}
string ret;
for (string row : rows) {// 从上到下遍历行
ret += row;
}
return ret;
}
};
字母下标有规则
string convert(string s, int numRows) {
if (numRows == 1) return s;
int step = numRows * 2 - 2; // 间距
int index = 0;// 记录s的下标
int len = s.length();
int add = 0; // 真实的间距
string ret;
for (int i = 0; i < numRows; i++) // i表示行号
{
index = i;
add = i * 2;
while (index < len)//超出字符串长度计算下一层
{
ret += s[index]; // 当前行的第一个字母
add = step - add;// 第一次间距是step -2*i,第二次是2*i,
index += (i == 0 || i == numRows-1) ? step : add; // 0行和最后一行使用step间距,其余使用add间距
}
}
return ret;
}
法1 数字转换字符串 to_string 字符串转换成数字 stoi
在C++中,std::stoi() 函数将字符串转换为整数。它的参数是 const std::string& 类型,可以表示一个包含数字的字符串。
对于 std::stoi() 函数,数字大小是有限制的,主要受到两个因素的影响:
整数类型的上限:在C++中,整数类型的上限由相应类型的数据表示范围决定。例如,如果使用 int 类型,则 std::numeric_limits::max() 代表该类型的最大值。如果尝试将超出这个范围的数字转换为 int 类型,std::stoi() 函数将引发 std::out_of_range 异常。
数字字符串本身的长度限制:如果尝试将太长的字符串转换为整数,std::stoi() 函数也会引发 std::out_of_range 异常。具体而言,在大多数实现中,字符串中的数字数量受到 size_t 类型的最大值(std::numeric_limitsstd::size_t::max()) 的限制。
综上所述,数字大小并非直接受到 std::stoi() 函数的限制,而是受到整数类型的数据表示范围和数字字符串长度的限制。
class Solution {
public:
int reverse(int x) {
string s = to_string(x);
int n = s.size();
string c;
if(s[0]=='-')
{
c.push_back('-');
for (int i = (n-1); i >0; i-- )
{
c.push_back(s[i]);
}
}
else{
for (int i = (n-1); i >=0; i--)
{
c.push_back(s[i]);
}
}
int b = stoi(c);
return b;}
};
class Solution {
public int reverse(int x) {
int res = 0;
while(x!=0) {
//每次取末尾数字
int tmp = x%10;
//判断是否 大于 最大32位整数
if (res>214748364 || (res==214748364 && tmp>7)) {
return 0;
}
//判断是否 小于 最小32位整数
if (res<-214748364 || (res==-214748364 && tmp<-8)) {
return 0;
}
res = res*10 + tmp;
x /= 10;
}
return res;
}
}
int reverse(int x) {
string s=to_string(x);//变成字符串
std::reverse(s.begin(), s.end());//翻转字符串 注意这里用了作用域 不然会有函数名的冲突
int ans=0;
try{
ans=stoi(s);//变回数字
if (x<0) ans=-ans;//x是负数,加上负号
}catch(exception ex){}//溢出,啥也不做,返回零
return ans;
}
另外,因为 std::exception 是标准库中的一个基类,不会抛出具体的异常类型,因此在 catch 块中应该使用 catch(const std::exception& e) 的方式捕获异常。而在本代码中,catch(exception e) 只捕获了一个未指定类型的异常,并没有处理异常。建议修改为 catch(const std::exception& e) {},即空的 catch 块,这样可以避免程序崩溃。
在 catch(const std::exception& e){} 中,通过引用方式传递异常对象的好处是可以避免对象的拷贝和构造,从而提高程序的运行效率和性能。
此外,为了保证异常对象不会被修改,通常会在参数类型前加上 const 关键字。这样做可以防止在捕获异常时误修改异常对象的状态。如果在程序中需要修改异常对象的状态,可以将其声明为非常量引用,例如:catch(std::exception& e)。
需要注意的是,在某些情况下,如果异常对象是由值传递方式传递的,则在 catch 块中使用对象名称时,会发生值复制和对象构造,因此建议在 catch 块中始终使用引用方式传递异常对象,以避免不必要的开销。
综上所述,通过在 catch 块中传递 const 引用,可以避免对象的拷贝和构造,提高程序的运行效率和性能,并保证异常对象的状态不被修改。
1-7
1 用了 try catch
2 使用字符串 数字抓换 to_string stoi
stoi会直接把s转换成数字 我看他代码里最后一位是符号的话不用管
3 不断地最后一位推出 除以10的余数
1 自动机 相当于状态机
开始状态 标识符状态 数字状态 结束状态
int get_col(char c) {
if (isspace(c)) return 0;
if (c == '+' or c == '-') return 1;
if (isdigit(c)) return 2;
return 3;
ans = ans * 10 + c - '0' 减去字符0的ascii值
不然相加都是加的字符的 ascii的值
ans = sign == 1 ? min(ans, (long long)INT_MAX) : min(ans, -(long long)INT_MIN);
我估计都必须是同型号的才能比较
2 字符流
#include
class Solution {
public:
int myAtoi(string s) {
stringstream liu(s);
int n=0;
liu>>n;
return n;
}
};
c++,活用cin
读取(和忽略)处于所需数据周围的标号,例如字符串是(“12 1”)int n,c; liu>>n>>c n的值是12,c的值是1
1 我想的是从中间扩散 他的是从两边到中间
2 第二个想法是将数字本身反转,然后将反转后的数字与原始数字进行比较,如果它们是相同的,那么这个数字就是回文。
但是,如果反转后的数字大于
int.MAX
int.MAX,我们将遇到整数溢出问题。
那为什么不反转数字的一半
class Solution {
public:
bool isPalindrome(int x) {
if(x<0)
return false;
string s = to_string(x);
int i=0 , j= s.length()-1;
while(i<=j)
{
if(s[i]!=s[j])
return false;
i++;
j--;
}
return true;
}
};
class Solution {
public:
bool isPalindrome(int x) {
string s=to_string(x);
int n=s.size();
if(s.length()<=1)
return true;
if(!isdigit(s[0]))
return false;
if(n%2==0)
{
int k=1;
for(int i = n/2; i<n; i++)
{
if(s[i]!=s[i-k])
return false;
k+=2;
}
}
else
{
int k=2;
for(int i = (n/2 +1); i<n; i++)
{
if(s[i]!=s[i-k])
return false;
k+=2;
}
}
return true;
}
};
bool isPalindrome(int x) {
if (x<0)return false;
if (x==0)return true;
string s=to_string(x);
int n=s.size();
for(int i=0;i<n/2;i++){
int j=n-1-i;
if(s[i]!=s[j]){
return false;
}
}
return true;
}
};
https://leetcode.cn/problems/regular-expression-matching/solution/by-flix-musv/
动态规划
dp[i][j] 表示s的前i个字符和p的前j个字符是否匹配·
原本是要看s的前i个字符和p的前j个字符是否匹配·
p[j]为* 他这里是往前看的 后面的会考虑到前面的
如果匹配两次 意味着 s的i-1和i的字符要相同 ,并且 p的j-1字符也要相同
那么 i,j的问题 就转化为了 i-2和j-2的问题 以此往前
同样,如匹配k次 那么i,j的问题便转化为i-k和j-2的匹配问题
匹配0次,那么i,j的问题就可以转化为i,j-2的问题
他用了两个方程进行转化
得到了简化的状态方程
最后他得出了三种情况的方程
1 i,j字符匹配
那么就是要找i-1和 j-1匹配
否则直接false
2,p[j]为* 那么接下来
看 s[i]和 p[j-1]是否相等
接下来又分两种情况
他这里提到了边界情况 两个都是空字符串那么 0,0位置
对于0,j 当j不是*时候,false 是的话 会引发j-2的情况 ,那么需要前面预留位置
class Solution {
public:
bool isMatch(string s, string p) {
if (p.empty()) return s.empty();
auto first_match = !s.empty() && (s[0] == p[0] || p[0] == '.');
if (p.length() >= 2 && p[1] == '*') {
return isMatch(s, p.substr(2)) || (first_match && isMatch(s.substr(1), p));
} else {
return first_match && isMatch(s.substr(1), p.substr(1));
}
}
};
class Solution {
public:
bool isMatch(string s, string p) {
if(regex_match(s,regex(p)))
{
return true;
}
return false;
}
};
class Solution {
public:
bool isMatch(string s, string p) {
return isMatch(s.c_str(), p.c_str());
}
bool isMatch(const char* s, const char* p) {
if(*p == 0) return *s == 0;
auto first_match = *s && (*s == *p || *p == '.');
if(*(p+1) == '*'){
return isMatch(s, p+2) || (first_match && isMatch(++s, p));
}
else{
return first_match && isMatch(++s, ++p);
}
}
};
class Solution {
public:
bool isMatch(string s, string p) {
int m = s.size();
int n= p.size();
vector<vector<bool>> dp(m+1, vector<bool>(n+1, false));
dp[0][0] = true;
for(int j=1; j<=n; j++)
{
if(p[j-1]=='*') dp[0][j] = dp[0][j-2];//按题意p第一个元素不可能为'*'所以不必担心j越界
}
for(int i=1; i<=m; i++)
{
for(int j=1; j<=n; j++)
{
if(s[i-1]==p[j-1] || p[j-1]=='.') dp[i][j] = dp[i-1][j-1];
else if(p[j-1]=='*')
{
if(s[i-1]!=p[j-2] && p[j-2]!='.')
{
dp[i][j] = dp[i][j-2];
}
else
{
dp[i][j] = dp[i][j-2] | dp[i-1][j];
}
}
}
}
return dp[m][n];
}
};
int maxArea(vector<int>& height) {
int max1=0;
int area=0;
int n = height.size();
for(int i=0;i<n-1;i++)
{
for(int j=i+1 ; j<n;j++)
{
area= min(height[i],height[j])*(j-i);
max1= max(area,max1);
}
}
return max1;
}
class Solution {
public:
int maxArea(vector<int>& height) {
int i = 0, j = height.size() - 1, res = 0;
while(i < j) {
res = height[i] < height[j] ?
max(res, (j - i) * height[i++]):
max(res, (j - i) * height[j--]);
}
return res;
}
};
class Solution {
public:
int maxArea(vector<int>& height) {
int i=0,j=height.size()-1,area1=0;
int max1=0;
while(i!=j)
{
area1= (j-i)*min(height[i],height[j]);
max1= max1>area1?max1:area1;
if(height[i]>height[j])
{
j--;
}
else
{
i++;
}
}
return max1;
}
};
长短板
两边 长的往里进 短的不变,长的变得更短,不可能变大
短的往里进 还有可能变大
小的在右边 加
小的在左边 减去
class Solution {
public:
int romanToInt(string s) {
// string x1[] = {"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
//String[] rom={"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
// int x2[] = {1000,900,500,400,100,90,50,40,10,9,5,4,1};
unordered_map<string,int> hashmap= { {"M",1000},{"CM",900},{"D",500},{"CD",400},{"C",100},{"XC",90},{"L",50},{"XL",40},{"X",10},{"IX",9},{"V",5},{"IV",4},{"I",1}};
int ans = 0;
//string ss="";
for(int i=0;i<s.length();i++)
{
if(i+1<s.length() )
{
string s1(1,s[i]);
string s2(1,s[i+1]);
if(hashmap[s1]>=hashmap[s2])
ans+=hashmap[s1];
else
{
ans+=hashmap[s1+s2];
i++;
}
}
else if(i==s.length()-1)
{
string s1(1,s[i]);
ans+=hashmap[s1];
}
}
return ans;
}
};
class Solution {
private:
unordered_map<char, int> symbolValues = {
{'I', 1},
{'V', 5},
{'X', 10},
{'L', 50},
{'C', 100},
{'D', 500},
{'M', 1000},
};
public:
int romanToInt(string s) {
int ans = 0;
int n = s.length();
for (int i = 0; i < n; ++i) {
int value = symbolValues[s[i]];
if (i < n - 1 && value < symbolValues[s[i + 1]]) {
ans -= value;
} else {
ans += value;
}
}
return ans;
}
};
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/roman-to-integer/solution/luo-ma-shu-zi-zhuan-zheng-shu-by-leetcod-w55p/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
使用单调栈
vector<int> mostCompetitive(vector<int>& nums, int k) {
int n = nums.size();
int count= n-k;
vector<int> ans;
for(int i = 0; i<n;i++)
{
while(!ans.empty() && ans.back()>nums[i] && count>0)
{
ans.pop_back();
count--;
}
ans.push_back(nums[i]);
}
while(ans.size()>k)
{
ans.pop_back();
}
return ans;
}
他这个课程表 课程数量和 有的课是相同的
for cur, pre in prerequisites:
indegrees[cur] += 1 [ xx] 在课程位置数加1 代表该课程的入度数加1
adjacency[pre].append(cur) 在 pre课程位置的 【】内加入 出度的课程号 即依赖这门课的后续课程
遍历 indegress 如果他的入度数为0 就把该位置相当于课号的加入 队列
此时 queue 应该是 按照课程号顺序排列的,并且都是入度数为0的,相当于第一层节点
当queue不为空,就不断推出队首的一个值,
然后根据这个值看依赖他的课程号,然后把该课程号的入度数减去1,并判断 这个课程入度数是否为0,是的话就推入queue
queue都遍历完了 然后 把 numcourses返回
DFS法
class Solution {
private:
vector<vector<int>> edges;
vector<int> visited;
bool valid = true;
public:
void dfs(int u) {
visited[u] = 1;
for (int v: edges[u]) {
if (visited[v] == 0) {
dfs(v);
if (!valid) {
return;
}
}
else if (visited[v] == 1) {
valid = false;
return;
}
}
visited[u] = 2;
}
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
edges.resize(numCourses);
visited.resize(numCourses);
for (const auto& info: prerequisites) {
edges[info[1]].push_back(info[0]);
}
for (int i = 0; i < numCourses && valid; ++i) {
if (!visited[i]) {
dfs(i);
}
}
return valid;
}
};
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/course-schedule/solution/ke-cheng-biao-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
广度优先
class Solution {
private:
vector<vector<int>> edges;
vector<int> indeg;
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
edges.resize(numCourses);
indeg.resize(numCourses);
for (const auto& info: prerequisites) {
edges[info[1]].push_back(info[0]);
++indeg[info[0]];
}
queue<int> q;
for (int i = 0; i < numCourses; ++i) {
if (indeg[i] == 0) {
q.push(i);
}
}
int visited = 0;
while (!q.empty()) {
++visited;
int u = q.front();
q.pop();
for (int v: edges[u]) {
--indeg[v];
if (indeg[v] == 0) {
q.push(v);
}
}
}
return visited == numCourses;
}
};
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/course-schedule/solution/ke-cheng-biao-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
vector<int> degrees(numCourses);//记录所有顶点的入度,未初始化的为0
vector<vector<int>> adjacents(numCourses); //邻接表
queue<int> zero;//零入度的顶点
int num = numCourses;
for(int i=0;i<prerequisites.size();i++)
{
degrees[prerequisites[i][0]]++;//入顶点
adjacents[prerequisites[i][1]].push_back(prerequisites[i][0]);//出顶点
}
for(int i=0;i<numCourses;i++)
if(degrees[i]==0){
zero.push(i); //入度为0的先入队列
num--;
}
while(!zero.empty()){
int temp = zero.front();
zero.pop();
for(int j=0;j<adjacents[temp].size();j++)
if(--degrees[adjacents[temp][j]]==0){
zero.push(adjacents[temp][j]);
num--;
}
}
if(num==0)
return true;
return false;
}
广度优先即按层去遍历整个图,一层访问结束后再去访问下一层。
https://blog.csdn.net/yanweiqi1754989931/article/details/109603384
https://blog.csdn.net/m0_46213598/article/details/120363633
建立依赖表 就是依赖这个课程的 课程
为每个课程建立0标签
对于每一个课程, if not dfs,返回假
不然返回真
dfs 是0的话就返回假了 基本上dfs得是1
dfs 三个参数 分别是 课程号 课程的依赖课 该课程的标签
对于i课程dfs中 对他的依赖课程dfs
要想这个不执行 得是他的依赖课程dfs都是 true
都执行完 ,该课程标签置为-1
就是判断是否有环,有环就不行了
我的想法是把字符串分成两半 再两边找
他直接是构建了一o, 然后拿s里的字母一个个到o里找
class Solution {
public:
bool halvesAreAlike(string s) {
string o = "aeiouAEIOU";
int n = s.length();
int cout1=0,cout2=0;
for(int i=0; i< n; i++ )
{
int pose1=o.find(s[i]);
if(pose1!= -1)
{
i<n/2? cout1++:cout2++;
}
}
if(cout1 ==cout2) return true;
else return false;
}
};
https://blog.csdn.net/hnjzsyjyj/article/details/108929993
priority queue元素 队列中元素按照优先级参数排序,最小或者最大的元素总是在队列前端,并且会在每次出队的时候被删除
greater 从大到小
priority_queue
q2;//神奇的降序
大家可以看到,默认模板有三个参数,第一个是优先队列处理的类。第二个参数比较有特点,是容纳优先队列的容器。实际上,优先队列是由这个容器C++语言中关于heap的相关操作实现的。这个容器默认是vector,也可以是dequeue,因为后者功能更强大,而性能相对于vector较差,考虑到包装在优先队列后,后者功能并不能很好发挥,所以一般选择vector来做这个容器。第三个参数比较重要,支持一个比较结构,默认是less,默认情况下,会选择第一个参数决定的类的<运算符来做这个比较函数。priority_queue
qi2;//从小到大的优先级队列,可将greater改为less,即为从大到小可以使用优先队列存储每个苹果的腐烂日期 最小元素会被先取出
看一下当天pq中已经过期的 直接删掉 然后加入当天新鲜的
当pq非空,并且他的top的first元素小于等于i pq插入 腐烂的天数以及腐烂的数目 推出top 然后把腐烂数目减1 然后如果还有数目
就加入只要pq不为空 一直执行循环 , 然后首先当天去掉过期的 再次判断 是不是空了 ,空的话就推出循环,不然就拿出top并推出 int num
= min(curr.first - i, curr.second); 分析两个数字中小的, 第一个是还有几天过期,比如两天过期, 第二个是还剩下几个苹果,比如三个苹果, 那么可以吃的数量就是两个 然后一个天数一个苹果树分别加上最小值
class Solution {
public:
int eatenApples(vector<int>& apples, vector<int>& days) {
int ans = 0;
int d = 0;
map<int, int> m; // (expire, cnt)
while (d < days.size() || !m.empty()) {
if (d < days.size()) m[days[d]+d-1] += apples[d];
// 尝试从map中取出一个最接近过期但是没有过期的苹果
while(!m.empty()) {
if (m.begin()->first < d || m.begin()->second == 0) m.erase(m.begin()->first);
else {
// 如果找到了 我们就吃掉它
ans++;
// 苹果数要减1
m.begin()->second--;
break;
}
}
d++;
}
return ans;
}
};
作者:wfnuser
链接:https://leetcode.cn/problems/maximum-number-of-eaten-apples/solution/wei-rao-li-lun-tan-xin-dui-mei-ci-zhao-z-txr2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
int eatenApples(vector<int>& apples, vector<int>& days) {
int ans = 0;
int d = 0;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
while (d < days.size() || !q.empty()) {
if (d < days.size()) q.push(make_pair(days[d]+d-1, apples[d]));
auto apple = q.top();
// 跳过所有已经过期的苹果
while (apple.first < d) {
q.pop();
if (q.size() == 0) break;
apple = q.top();
}
// 如果没有没过期的苹果,继续下一天的等待
if (q.size() == 0) { d++; continue; }
// 如果有可以吃的苹果;我们要把这一天过期的苹果数量减1
if (apple.second > 0) {
q.pop();
apple.second--;
// 如果苹果还有剩余,我们把它放回堆中
if (apple.second > 0) q.push(apple);
ans++;
}
d++;
}
return ans;
}
};
作者:wfnuser
链接:https://leetcode.cn/problems/maximum-number-of-eaten-apples/solution/wei-rao-li-lun-tan-xin-dui-mei-ci-zhao-z-txr2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
typedef pair<int,int> pii;
class Solution {
public:
int eatenApples(vector<int>& apples, vector<int>& days) {
int ans = 0;
priority_queue<pii, vector<pii>, greater<pii>> pq;
int n = apples.size();
int i = 0;
while (i < n) {
while (!pq.empty() && pq.top().first <= i) {
pq.pop();
}
int rottenDay = i + days[i];
int count = apples[i];
if (count > 0) {
pq.emplace(rottenDay, count);
}
if (!pq.empty()) {
pii curr = pq.top();
pq.pop();
curr.second--;
if (curr.second != 0) {
pq.emplace(curr.first, curr.second);
}
ans++;
}
i++;
}
while (!pq.empty()) {
while (!pq.empty() && pq.top().first <= i) {
pq.pop();
}
if (pq.empty()) {
break;
}
pii curr = pq.top();
pq.pop();
int num = min(curr.first - i, curr.second);
ans += num;
i += num;
}
return ans;
}
};
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/maximum-number-of-eaten-apples/solution/chi-ping-guo-de-zui-da-shu-mu-by-leetcod-93ka/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
vector<int> findBall(vector<vector<int>>& grid) {
int col = grid[0].size();
vector<int> res;
for(int i=0; i<col;i++)
{
int j =0;
while(j<grid.size())
{
int cur = grid[j][i];
i+= grid[j][i]; //action
if(i>=0 ||i<col)
{
int nei = grid[j][i];
if(nei*cur>0) j++;
else
break;
}
}
j==grid.size()-1? res.push_back(i+1):res.push_back(-1);
}
return res;
}
};
vector<int> findBall(vector<vector<int>> &grid) {
int n = grid[0].size();
vector<int> ans(n);
for (int j = 0; j < n; ++j) {
int col = j; // 球的初始列
for (auto &row : grid) {
int dir = row[col];
col += dir; // 移动球
if (col < 0 || col == n || row[col] != dir) { // 到达侧边或 V 形
col = -1;
break;
}
}
ans[j] = col; // col >= 0 为成功到达底部
}
return ans;
}
考虑col中的数字为方向,然后根据方向更新col,此时看col是否为边界,并看此时col中的数字是否一致,不然的话条件不满足,球被卡死,无法进入到下一层。
递归
首先判断是不是空指针 是的话返回{}
然后判断他的左右节点是不是空 是的话返回0
设立了一个 vector ret
遍历左系欸但 返回的left是
/ 他是按层来的,从下往上。 最下面的叶子计算层数,比方说左和右,计算距离。
计算完成后返回上一层dfs,此时的下层的左和右都会统一变成上一层的左 或者是 右。
class Solution {
public:
int countPairs(TreeNode* root, int distance) {
int ans = 0;
dfs(root, distance, ans);
return ans;
}
vector<int> dfs(TreeNode* root, int distance, int& ans) {
if (root == nullptr) return {};
if (root->left == nullptr && root->right == nullptr) return { 0 };
vector<int> ret;
auto left = dfs(root->left, distance, ans);
for (auto& e : left) {
if (++e > distance) continue;
ret.push_back(e);
}
auto right = dfs(root->right, distance, ans);
for (auto& e : right) {
if (++e > distance) continue;
ret.push_back(e);
}
for (auto l : left) {
for (auto r : right) {
ans += (l + r <= distance);
}
}
return ret;
}
};
静态连通
给定整个图 再给出连通性的询问
https://leetcode.cn/problems/check-if-there-is-a-valid-path-in-a-grid/solution/jian-cha-wang-ge-zhong-shi-fou-cun-zai-you-xiao-lu/
并查集
class Solution {
int m,n,dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};//0下、1右、2上、3左
int pipe[7][4]={{-1,-1,-1,-1},{-1,1,-1,3},{0,-1,2,-1},{-1,0,3,-1},{-1,-1,1,0},{3,2,-1,-1},{1,-1,-1,2}};
//记录各个拼图块路径的方向,0、1、2、3代表方向,-1代表不可走。
bool dfs(int x,int y,int dir,vector
if(xm-1&&yn-1) return 1;//到达终点
int xx=x+dx[dir];
int yy=y+dy[dir];//得到下一个准备走的坐标
if(xx<0||yy<0||xx>=m||yy>=n)return 0;//越界
int nxt=grid[xx][yy];//得到下一块拼图的编号
if(pipe[nxt][dir]!=-1)return dfs(xx,yy,pipe[nxt][dir],grid);//如果当前方向可走,则方向改变,继续走。
return 0;//无法走,返回0
}
public:
bool hasValidPath(vector
m=grid.size();
n=grid[0].size();
int sta=grid[0][0];//起点的拼图编号
for(int i=0;i<4;++i)//朝着四个方向都试一下
if(pipe[sta][i]!=-1)//当前方向可以走
if(dfs(0,0,pipe[sta][i],grid))//沿着当前方向搜索
return 1;//拼图都有两个方向可以走,只要沿着一个初始方向走通就可以。
return 0;
}
};
作者:wu-xing-que-ni-2
链接:https://leetcode.cn/problems/check-if-there-is-a-valid-path-in-a-grid/solution/cdfsjie-fa-rong-yi-li-jie-dai-ma-duan-zhu-shi-duo-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
暴力枚举
string temp=to_string(num);
reverse(temp.begin(),temp.end());
return stoi(temp);
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums)
{
vector< vector<int> > ans;
if(nums.size() < 3 || nums.empty()) return ans; // 特判
int n = nums.size();
sort(nums.begin(), nums.end()); //排序
for(int i = 0; i < n; i++) // 枚举最小值
{
if(nums[i] > 0) return ans;
if(i > 0 && nums[i] == nums[i-1]) continue; // 最小元素去重!
int l = i+1;
int r = n-1;
while(l < r) // 枚举中间值和最大值
{
int x = nums[l] + nums[r] + nums[i];
if(x == 0){ // 符合条件,存储,并且去重,双端都移到下一个位置
ans.push_back({ nums[i], nums[l], nums[r] });
while( l < r && nums[l] == nums[l+1]) l++; l++;
while( l < r && nums[r] == nums[r-1]) r--; r--;
}
else if(x > 0) // 大了就让右边最大值变小
r--;
else // 小了就让左边中间值变大
l++;
}
}
return ans;
}
};
https://blog.csdn.net/weixin_44020969/article/details/103225825
https://leetcode.cn/problems/range-product-queries-of-powers/
class Solution {
public:
vector<int> two(int &n)
{
vector<int> ans;
int i=0;
while(n>0)
{
if(n&1)
{
ans.push_back(1 << i);
}
n >>= 1;
i++;
}
//reverse(ans.begin(),ans.end());
return ans;
}
vector<int> productQueries(int n, vector<vector<int>>& queries) {
vector<int> power= two(n),ans;
for(int i=0;i<queries.size();i++)
{
int j = queries[i][0];
long tem = 1;
while(j<=queries[i][1])
{
tem = tem*power[j]%1000000007;
j++;
}
ans.push_back(tem);
tem = 1;
}
return ans;
}
};
class Solution {
public:
vector<int> productQueries(int n, vector<vector<int>>& queries) {
const int MOD = 1e9 + 7;
vector<int> powers, prefix;
long long tmp = n, base = 1;
while (tmp > 0) {
if (tmp & 1) powers.push_back(base);
base = (base * 2LL) % MOD;
tmp >>= 1;
}
prefix.push_back(1);
for (int i = 0; i < powers.size(); ++i) {
prefix.push_back((long long)prefix.back() * powers[i] % MOD);
}
vector<int> answers;
for (auto& query : queries) {
int left = query[0], right = query[1] + 1;
long long res = (long long)prefix[right] * inverse(prefix[left], MOD) % MOD;
answers.push_back(res);
}
return answers;
}
private:
int inverse(int a, int m) {
int m0 = m, t, q;
int x0 = 0, x1 = 1;
if (m == 1) return 0;
while (a > 1) {
q = a / m;
t = m;
m = a % m;
a = t;
t = x0;
x0 = x1 - q * x0;
x1 = t;
}
if (x1 < 0) x1 += m0;
return x1;
}
};
int numberOfBeams(vector<string>& bank) {
int row = bank.size();
int las1=0;
vector<int> num;
int ans;
for(int i=0; i<row; i++)
{
for(char c:bank[i])
{
if(c=='1')
las1++;
}
if(las1!=0)
num.push_back(las1);
las1=0;
}
for(int i=0; i<num.size()-1; i++)
{
int tem= num[i]*num[i+1];
ans+=tem;
}
return ans;
}
class Solution {
public:
int numberOfBeams(vector<string>& bank) {
int res = 0;
int pre = 0;
for (auto &s : bank) {
int cur = 0;
for (char &c : s) {
cur += c == '1';
}
if (cur > 0) {
res += pre * cur;
pre = cur;
}
}
return res;
}
};
class Solution {
public:
int numberOfBeams(vector<string>& bank) {
int last = 0, ans = 0;
for (const string& line: bank) {
int cnt = count_if(line.begin(), line.end(), [](char ch) {return ch == '1';});
if (cnt != 0) {
ans += last * cnt;
last = cnt;
}
}
return ans;
}
};
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/number-of-laser-beams-in-a-bank/solution/yin-xing-zhong-de-ji-guang-shu-shu-liang-ad02/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
bool validMountainArray(vector<int>& arr) {
int n = arr.size();
if(n<3) return false;
int flag=0;
for(int i=0;i<n-1;i++)
{
if(flag==0)
{
if(arr[i]>=arr[i+1]) return false;
if(arr[i]<arr[i+1]) flag=1;
}
else if(flag==1)
{
if(arr[i]==arr[i+1]) return false;
if(arr[i]>arr[i+1]) flag=2;
}
else
{
if(arr[i]<=arr[i+1]) return false;
}
}
if(flag==2)
return true;
else
return false;
}
};
class Solution {
public:
bool validMountainArray(vector<int>& arr) {
int n = arr.size();
if(n<3) return false;
int flag=0;
for(int i=0;i<n-1;i++)
{
if(flag==0)
{
if(arr[i]>=arr[i+1]) return false;
if(arr[i]<arr[i+1]) flag=1;
}
else if(flag==1)
{
if(arr[i]==arr[i+1]) return false;
if(arr[i]>arr[i+1]) flag=2;
}
else
{
if(arr[i]<=arr[i+1]) return false;
}
}
if(flag==2)
return true;
else
return false;
}
};
const validMountainArray = (A) => {
const n = A.length;
let i = 0;
let j = n - 1;
while (i + 1 < n && A[i] < A[i + 1]) {
i++;
}
while (j - 1 >= 0 && A[j - 1] > A[j]) {
j--;
}
if (i != 0 && i == j && j != n - 1) {
return true;
}
return false;
};
可以使用两种指针,一个从左边找最高山峰,一个从右边找最高山峰,最后判断找到的是不是同一个山峰
思路 直接统计两个字符串中 不同字符的个数 是否相同
class Solution {
public:
bool closeStrings(string word1, string word2)
{
int m = word1.size();
int n = word2.size();
if (m != n)
return false;
vector<int> repeat1(26, 0), repeat2(26, 0);
for (int i = 0; i < m; ++i)
{
++repeat1[word1[i] - 'a'];
++repeat2[word2[i] - 'a'];
}
for (int i = 0; i < 26; ++i)
if ((repeat1[i] == 0) ^ (repeat2[i] == 0)) 异或运算符 其实就是判断两个 如果一个是0 一个不是 那么不成立
return false; 我想着把这段删了 只要下面的for就行,但是不太行
sort(repeat1.begin(), repeat1.end()); 因为这里只是 数量对上了 转换后字母不同
例如 "uau" "ssx"
sort(repeat2.begin(), repeat2.end());
for (int i = 0; i < 26; ++i)
if (repeat1[i] != repeat2[i])
return false;
return true;
}
};
作者:Dahri
链接:https://leetcode.cn/problems/determine-if-two-strings-are-close/solution/tong-ji-zi-fu-de-chu-xian-ci-shu-jiu-hao-liao-by-p/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
我的思路 滑动窗口法,最大宽度从 n 开始不断往下减少
一开始最大n只有一个 上标0 下标n-1
后面有两个 上标0或者1 下标 n-2 或者 n-1
class Solution {
public:
int maxWidthRamp(vector<int>& nums) {
int n=nums.size()-1;
int k=nums.size()-1;
while(n>0)
{
for(int i=0; i<=k-n;i++)
{
if(nums[i]<=nums[n+i])
return n;
}
n--;
}
return 0;
}
};
超出时间限制
单调递增栈就是从栈底到栈顶是从小到大;
单调递减栈就是从栈底到栈顶是从大到小。
他这里构建的代码就是 栈底元素最大 顶部元素最小,从nums中标号0开始的
然后 nums 栈顶标号元素 小于 nums j 就给到栈顶pos,然后推出
class Solution
{
public:
int maxWidthRamp(vector<int> &nums)
{
stack<int> s;
int res = 0;
int n = nums.size();
s.push(0);
for (int i = 0; i < n; ++i)
{
if (s.empty() || nums[s.top()] > nums[i])
s.push(i); // 严格单调递减栈
}
for (int j = n - 1; j >= res; --j) // 当然你要写成j >= 0也是可以AC的
{
while (s.size() && nums[s.top()] <= nums[j])
{
int pos = s.top();
s.pop();
res = max(res, j - pos);
}
}
return res;
}
};
作者:Algo-Goer
链接:https://leetcode.cn/problems/maximum-width-ramp/solution/c-962-zui-da-kuan-du-po-ti-jie-dan-diao-5ztod/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
def maxWidthRamp(A):
stack = []
max_width = 0
# 构建单调递减栈
for i, num in enumerate(A):
if not stack or A[stack[-1]] > num:
stack.append(i)
# 从右向左遍历数组,查找最大宽度坡
for j in range(len(A) - 1, -1, -1):
while stack and A[stack[-1]] <= A[j]:
i = stack.pop()
max_width = max(max_width, j - i)
return max_width
作者:3k5X21s3ar
链接:https://leetcode.cn/problems/maximum-width-ramp/solution/bao-jiao-bao-hui-shi-jian-fu-za-du-onkon-3lji/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
解题思路:使用递减栈求解该最大跨度问题“找到满足 A[j] >= A[i] 的最大跨度 [i,j]”。
理论依据:1.栈中保存的元素依次为比 A 首元素逐步降低的元素索引,对于任意区间 [i,j] ,无妨设 i 不是栈顶元素,若其满足 A[j] >= A[i] ,则对于栈中比 i 小的最大索引 i_0 < i (此时 i_0 是正序遍历至 i 处时的栈顶元素),区间 [i_0,j] 必满足 A[j] > A[i_0] ,这是因为栈顶元素是递减的,因为 i 元素不在栈中而 i_0 是正序遍历至 i 处时的栈顶元素,故必有 A[i_0] < A[i] ,即区间 [i_0,j] 是比区间 [i,j] 更优的解,故,对于最优解的区间 [i,j] , i 必是某个栈顶元素;
i_0是栈里的,单调递减,他的元素起码小于等于 i上的元素,所以条件更成立,并且i_0还是小于i
相当于从0开始依次检测是否入栈,严格小于栈顶的才入栈
之后比方说到了 数组的i位置处,i的元素不足以入栈,当前的栈顶元素i_0所代表的,值比i
的小,位置也比他考前,所以理应更比他适合
2.在将 j 从 A 尾元素向左移动的过程中,若 A[j] >= A[heightStack.top()] 则可以将 heightStack.top() 弹出,因为 heightStack.top() 成为跨度左界的情况的跨度最大值已计算完毕,否则可以将 j 向左移动一位,因为 j 成为跨度右界的情况的跨度最大值已计算完毕,这是因为若 A[j] 小于当前栈顶元素,则 A[j] 必小于栈中其他元素。
算法过程:首先基于 A 数组构造递减栈;随后使用递减栈求出满足 A[j] >= A[i] 的最大跨度 [i,j] ,具体地,从 A 尾元素开始移动 j ,若 A[j] >= A[heightStack.top()] 则将 heightStack.top() 弹出,否则将 j 向左移动一位。
算法细节:当递减栈弹出至空时,可提前结束查找。
这里再前面建立单调栈的基础上,将整个数组的元素 从右往左逐个检验,
栈底到栈顶是从小到大
栈顶先出,栈底后出
先出大的,后出小的,所以单调递减
构造递减栈, 遍历,只要比栈顶小,就推入,从而越来越小,压在里面的是最大的。
栈中元素从深到浅 依次为 比首元素 减小的 元素索引
那么索引可能是
0 1 2 3 索引不断增大,先出3,再出2,
class Solution {
public:
int maxScore(vector<int>& nums) {
//int score = 0;
double num =0;
//vector prefix;
sort(nums.begin(),nums.end(),greater<int>());
int i=0;
while(num>=0)
{
num+=nums[i];
i++;
if(num<=0)
{
i--;
break;}
if(i>=nums.size()) break;
}
return i;
}
};
class Solution {
public int maxScore(int[] nums) {
// 从小到大排序
Arrays.sort(nums);
int maxScore = 0;
// 前缀和
long preFixSum = 0;
// 倒序求正数前缀和
for (int i = nums.length - 1; i >= 0; i--) {
preFixSum += nums[i];
if (preFixSum > 0) {
maxScore++;
} else {
// 出现负数,终止遍历
// nums的分数是prefix数组中正整数的个数
return maxScore;
}
}
return maxScore;
}
}
作者:fa-xing-bu-luan
链接:https://leetcode.cn/problems/rearrange-array-to-maximize-prefix-score/solution/6316-zhong-pai-shu-zu-yi-de-dao-zui-da-q-ofi7/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
遍历将数位和求出并加入map
然后遍历map map后面的值的长度大于二,就将v排序,从大到小,取前两个相加。
map<int, vector<int>> mp;
class Solution {
public:
int maximumSum(vector<int>& nums) {
map<int, vector<int>> mp;
for(auto c : nums){
int sum = 0, t = c;
while(c){
sum += c % 10;
c /= 10;
}
mp[sum].push_back(t);
}
int ans = -1;
for(auto [k, v] : mp){
if(v.size() == 1) continue;
sort(begin(v), end(v));
int n = v.size();
ans = max(v[n-1] + v[n-2], ans);
}
return ans;
}
};
一种思想就是 遍历每一条路径 ,然后把该路径的值计算
一种思想就是 每一层 然后每一层判断
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<vector<int>> ret;
vector<int> path;
void dfs(TreeNode* root, int target) {
if (root == nullptr) {
return;
}
path.emplace_back(root->val);
target -= root->val;
if (root->left == nullptr && root->right == nullptr && target == 0) {
ret.emplace_back(path);
}
dfs(root->left, target);
dfs(root->right, target);
path.pop_back();
}
vector<vector<int>> pathSum(TreeNode* root, int target) {
dfs(root, target);
return ret;
}
};
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/er-cha-shu-zhong-he-wei-mou-yi-zhi-de-lu-jing-lcof/solution/er-cha-shu-zhong-he-wei-mou-yi-zhi-de-lu-68dg/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
https://leetcode.cn/problems/minimum-number-of-arrows-to-burst-balloons/solution/tu-jie-tan-tao-wei-shi-yao-yao-an-qu-jian-de-you-d/
贪心。 右边断点从小到大排序,然后以右端点为参考点, 不断判断下一个的左端点是否小于,是的话判断下一个, 直到不是 那么这个时候弓箭加1
按左端右端排序都是一样的,都是寻求最小交集区间。[0,9]和[0,6]交集[0,6],所以[0,6]上可以一箭射穿,[0,6]和[7,8]没有交集,所以箭数+1。
class Solution {
public:
static bool cmp(vector<int> &a,vector<int> &b)
{
return a[1] < b[1];
}
int findMinArrowShots(vector<vector<int>>& points)
{
//贪心策略:和 LeetCode 435 无重叠区间是同一个意思
const int n = points.size();
if(n < 2) return n;
std::sort(points.begin(), points.end(), cmp);//按气球的结束坐标大小,对升序排列
int ans = 1;//不相交的气球个数 = 引爆全部气球需要的弓箭数量
int tail = points[0][1];//前一个不相交的气球结束坐标
for(int i = 1; i < n; ++i)
{
if(points[i][0] > tail)//不相交的条件:后一个气球的开始坐标大于(不能等于)前一个气球的结束坐标
{
++ans;
tail = points[i][1];
}
}
return ans;
}
};
sort(points.begin(), points.end(), [](const vector<int>& a, const vector<int>&b){
return a[1] < b[1];//这里a[0]
});
int start = points[0][0];
int end = points[0][1];
int sum = 1;
for(int i = 1; i < points.size(); i++) {
if(points[i][0] > end || points[i][1] < start) {
sum++;
start = points[i][0];
end = points[i][1];
}
else {
start = max(start, points[i][0]);
end = min(end, points[i][1]);
}
}
return sum;
}
3[a2[c]]
推着入栈 pair(num,string)
首先是 3 然后 【 表示开始
记录3 和前面的字符串为空
记录下a ,
然后遇到了2,前面的字符串为a
pair 2,a
记录【 新的开始 c
遇到了结束
表示 2 前面有a 然后
a 与 两个 c
变成acc,
然后又遇到了结束,这一层是 3 与空字符
表示 这一层 空字符 加上 3个acc
string decodeString(string s) {
//两个栈分别压int res和用pair
stack<pair<int, string>> sta;
int num = 0; string res = "";
//循环检查字符串
for (int i = 0; i < s.size(); i++) {
//遇到数字则存入num
if (s[i] >= '0'&&s[i] <= '9') {
num *= 10;
num += (s[i] - '0');//这里括号是否需要
}
else if (s[i] == '[') {//遇到[压栈数字和字符串,置零置空
sta.push(make_pair(num, res));
num = 0;
res = "";
}
else if (s[i] == ']') {//遇到]出栈数字和字符串,组装
int n = sta.top().first;//n指示的是res的循环次数,不是a的
string a = sta.top().second;
sta.pop();
for (int i = 0; i < n; i++) a = a + res; //循环n次
res = a;
}
else {//遇到字符存入字符
res += s[i];
}
}
return res;
}
https://blog.csdn.net/weixin_47138280/article/details/110548737
class Solution:
def arrayRankTransform(self, arr: List[int]) -> List[int]:
ranks = {v: i for i, v in enumerate(sorted(set(arr)), 1)}
return [ranks[v] for v in arr]
首先是 set()类型转换
然后sorted 排序
enumerate遍历
返回的 序列号 i 和 元素v
构建键值对 v:i
构建【】,里面 循环遍历arr中的元素 v作为 键取出值,然后按顺序
class Solution {
public:
vector<int> arrayRankTransform(vector<int>& arr) {
set<int> s;
for(int i=0;i<arr.size();i++)
{
s.insert(arr[i]);
}
for(int i=0;i<arr.size();i++)
{
set<int>::iterator pos= s.find(arr[i]);
//int k= (int)(pos-s.begin());
int k = distance(s.begin(),pos);
arr[i]=++k;
}
return arr;
}
};
#include
class Solution {
public:
vector<int> arrayRankTransform(vector<int>& arr) {
vector<int> idx(arr.size());
iota(idx.begin(), idx.end(), 0); 赋值0到n
sort(idx.begin(), idx.end(), [r = arr.data()](int a, int b){return r[a] < r[b];});
这里已经是按照arr中的从小到大 对0到n排序了 相当于对idx排序,如果r[1]最小 r[0]最大 相当于
【1,2,3,0】 他题目中要求的是数字当前的位置
int rk = 0, rear = INT_MIN;
for(int x: idx){ 遍历 idx中元素,相当于从小到大遍历 arr元素, arr【i】处的位置应当是当前第几个最小值,与上一个最小值相比,相等的话,该元素索引当前位置就变为相同的数,不然就是变为第几个最小的值
if(arr[x] != rear) ++rk; 这里做的相当于核实校准
rear = arr[x]; 把这个值给到目前比较值 如果后面的值一样大 就不会rk++了
arr[x] = rk;
}
return arr;
}
};
iota(idx.begin(), idx.end(), 0); 对一个范围内进行赋值 从 0到n
这行代码使用了STL中的iota函数,它将起始点为0、步长为1的连续的整数填充到容器idx的迭代器范围内,其中idx.begin()为迭代器范围的起始位置,idx.end()为结束位置。简单来说,这行代码为idx中的每个元素赋值从0开始递增的连续整数。
std::sort(idx.begin(), idx.end(), [&v](size_t i1, size_t i2) { return v[i1] < v[i2]; });
http://c.biancheng.net/view/3741.html
其中 capture 是捕获列表,params 是参数表,opt 是函数选项,ret 是返回值类型,body是函数体。
https://zhuanlan.zhihu.com/p/384314474
https://blog.csdn.net/u014072827/article/details/119736781
n个节点 n-1条边
每个节点至多一条出边
设立一个长度为 n,值都是n 的 distance 表,
然后循环 只要 x不等于-1 并且他的dis 对应节点的距离没算出来
当前到达位置的距离给入 dis 并且 d+1 ,然后查看下一个节点。
x能到达点的距离都算出来了
for i,d1,d2 in zip(range(n),cal(node1),cal(node2))
node1 和node2 都能访问到的节点, 最小化一个最大值
class Solution {
public:
vector<int> cal(vector<int> &edges ,int &node)
{
vector<int> dis(edges.size(), edges.size());
int d=0;
for(int i= node; i>=0 && dis[i]==edges.size();i=edges[i] )
{
dis[i] = d++;
}
return dis;
}
int closestMeetingNode(vector<int>& edges, int node1, int node2) {
vector<int> dis1 = cal(edges,node1);
vector<int> dis2 = cal(edges, node2);
int ma =edges.size();
int ans=-1;
for(int i=0 ; i<dis1.size();i++)
{
int d =max(dis1[i],dis2[i]);
if( d<ma)
{
ma =d;
ans = i;
}
}
return ans;
}
};
class Solution {
public:
vector<int> luckyNumbers (vector<vector<int>>& matrix) {
//int row = matrix.size();
int max1=0;
vector<int> ans;
//int col = matrix[0].size();
for(int i =0; i<matrix.size(); i++)
{
int rmin = *min_element(matrix[i].begin(),matrix[i].end());
auto minPosition = min_element(matrix[i].begin(),matrix[i].end()) - matrix[i].begin();
for(int j=0;j<matrix.size();j++)
{
max1=max(max1,matrix[j][minPosition]);
}
if(max1==rmin)
ans.push_back(max1);
max1=0;
}
return ans;
}
};
https://leetcode.cn/problems/find-closest-node-to-given-two-nodes/solution/by-lfool-t4y7/
class Solution {
public:
int closestMeetingNode(vector<int> &edges, int node1, int node2) {
int n = edges.size(), min_dis = n, ans = -1; 多少条边
auto calc_dis = [&](int x) -> vector<int> {
vector<int> dis(n, n); 创建n个n的 vector
for (int d = 0; x >= 0 && dis[x] == n; x = edges[x])
dis[x] = d++;
return dis;
};
其实就是这个节点到每个节点的距离
上面做的就是设立一个函数 给到一个节点x,如果节点存在并且他的位置还是n说明没算过
比方说[2,2,3,-1], 给了节点1,那么 创建节点1的dis vector
满足1>=0 dis[1] ==n, dis[1] =0; d=1
然后 x = edges[1], 相当于到2了,x变成2,2满足,那么dis[2]为1
然后一路往下直到该路线的尽头
另一个节点同理 直到该路线的尽头
对于两个dis vector
这两个节点到一个节点的距离较大值最小
遍历两个vector的每个点的最大值, 就是两个节点都能到达的点的距离最小,然后返回ans
auto d1 = calc_dis(node1), d2 = calc_dis(node2);
for (int i = 0; i < n; ++i) {
int d = max(d1[i], d2[i]);
if (d < min_dis) {
min_dis = d;
ans = i;
}
}
return ans;
}
};
作者:endlesscheng
链接:https://leetcode.cn/problems/find-closest-node-to-given-two-nodes/solution/ji-suan-dao-mei-ge-dian-de-ju-chi-python-gr2u/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
他这里处理的比我巧妙
if (i == n - 1 || s[i] != s[i + 1]) {
class Solution {
public:
vector<vector<int>> largeGroupPositions(string s) {
vector<vector<int>> ret;
int n = s.size();
int num = 1;
for (int i = 0; i < n; i++) {
if (i == n - 1 || s[i] != s[i + 1]) {
if (num >= 3) {
ret.push_back({i - num + 1, i});
}
num = 1;
} else {
num++;
}
}
return ret;
}
};
作者:LeetCode-Solution
链接:https://leetcode.cn/problems/positions-of-large-groups/solution/jiao-da-fen-zu-de-wei-zhi-by-leetcode-so-fi3n/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
vector<vector<int>> largeGroupPositions(string s) {
vector<vector<int>> ans;
vector<int> idx;
int num=1;
//char pre = s[0];
for(int i=0; i<s.size()-1;i++)
{
if(s[i]==s[i+1])
{
num++;
idx.push_back(i);
if(i+1 ==s.size()-1 && num>=3) 这里就是两个两个比 然后这里的if其实就是判断防止最后的遗漏,因为如果没,我是要不相等了他才会加入, 这里就是防止一直是相等的 然后到最后了,给他加入
{
int beg =idx[0];
int end =idx[idx.size()-1]+1;
idx={};
idx.push_back(beg);
idx.push_back(end);
ans.push_back(idx);
}
}
else
{
if(num>=3)
{
int beg =idx[0];
int end =idx[idx.size()-1]+1;
idx={};
idx.push_back(beg);
idx.push_back(end);
ans.push_back(idx);
}
num=1;
idx={};
}
}
return ans;
}
};
vector<vector<int>> largeGroupPositions(string s) {
vector<vector<int>> ans;
vector<int> idx;
if(s.length()<3)
return ans;
for(int i=0; i< s.length()-2; i++)
{
if(s[i]== s[i+1] && s[i+1] == s[i+2])
{
int beg =i;
int add = 2;
while(i+add <s.length() && s[i+2]==s[i+add+1])
{
add++;
}
ans.push_back({i,i+add});
i= i+add;
}
}
return ans;
}
参考leecode
https://leetcode.cn/problems/er-cha-shu-de-zui-jin-gong-gong-zu-xian-lcof/solution/mian-shi-ti-68-ii-er-cha-shu-de-zui-jin-gong-gon-7/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || p == root || q == root) {
return root;
}
TreeNode l = lowestCommonAncestor(root.left, p, q);
TreeNode r = lowestCommonAncestor(root.right, p, q);
return l == null ? r : (r == null ? l : root);
}
}
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(!root||root==p||root==q) return root;
TreeNode* l = lowestCommonAncestor(root->left, p, q);
TreeNode* r = lowestCommonAncestor(root->right, p, q);
return l?(r?root:l):r;
}
};
code block
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
//1.如果找不到p或q就返回null,如果找的到就返回该点 ps:我觉得return root设计的很巧妙
if(root == null || root == p || root == q) return root;
//2.如果左子树中有p或q,那么就会返回找到的点。或者p和q都有,就返回pq的公共点。或者p或q都没有就返回null。
TreeNode left = lowestCommonAncestor(root.left, p, q);
//3.如果右子树中有p||q,那么就会返回找到的点。或者p和q都有,就返回pq的公共点。或者p或q都没有就返回null。
TreeNode right = lowestCommonAncestor(root.right, p, q);
//4.left==null 说明:左子树中没有p或q(往上看最开始的判断语句:找不到就返回null)
// 5.直接返回right的原因,需要结合递归的思想多方面思考。
if(left == null) return right;
//6.运行到此处说明左子树中找到了p或q点。
if(right == null) return left;
//7.运行到此处说明p和q都找到了,root为最近的公共祖先。(该语句只会运行一次)
return root;
}
}