主要是 哈希表进行优化;
重点是 map的find; it->second ;以及 it != hastable.end();
class Solution {
public:
vector twoSum(vector& nums, int target) {
maphastable;
for(int i=0;ires;
for(int i=0;i=it->second){
continue;
}
res.push_back(i);
res.push_back(it->second);
break;
}
}
return res;
}
};
滑动窗口:
什么是滑动窗口?
其实就是一个队列,比如例题中的 abcabcbb,进入这个队列(窗口)为 abc 满足题目要求,当再进入 a,队列变成了 abca,这时候不满足要求。所以,我们要移动这个队列!
如何移动?
我们只要把队列的左边的元素移出就行了,直到满足题目要求!
一直维持这样的队列,找出队列出现最长的长度时候,求出解!
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s.size() == 0) return 0;
unordered_set lookup;
int maxStr = 0;
int left = 0;
for(int i = 0; i < s.size(); i++){
while (lookup.find(s[i]) != lookup.end()){//找到的话;
lookup.erase(s[left]);
left ++;
}
maxStr = max(maxStr,i-left+1);
lookup.insert(s[i]);
}
return maxStr;
}
};
class Solution {
public:
double findMedianSortedArrays(vector& nums1, vector& nums2) {
int m=nums1.size();
int n = nums2.size();
vectorans;
int pos1=0,pos2=0;
while(pos1=m){
for( ; pos2=n){
for( ; pos1
中心扩散法子;
1、从每一个位置出发,向两边扩散即可。遇到不是回文的时候结束
首先往左寻找与当期位置相同的字符,直到遇到不相等为止。
然后往右寻找与当期位置相同的字符,直到遇到不相等为止。
最后左右双向扩散,直到左和右不相等。
为什么是这样呢??
如果长度是单数,那么很明显,最中心的是一个字符;而结果是偶数 的话,那么中心就是两个字符,并且相同。
class Solution {
public:
string longestPalindrome(string s) {
//中心扩散法:从每个字母开始 进行扩散遍历判断;
int n=s.size();
int left = 0;
int right = 0;
int len = 1; //记录选择的字符字串长度
int maxStart = 0;
int maxLen = 0;
for (int i = 0; i < n; i++) {
len=1;
left = i - 1;
right = i + 1;
while (left >= 0 && s[left]==s[i]) {
len++;
left--;
}
while (right < n && s[right]==s[i]) {
len++;
right++;
}
while (left >= 0 && right < n && s[left]==s[right]) {
len = len + 2;
left--;
right++;
}
if (len > maxLen) {
maxLen = len;
maxStart = left;
}
}
return s.substr(maxStart+1,maxLen);
}
};
弹出最后的数字,
压入;
while循环进行倒转;;;
class Solution {
public:
int reverse(int x) {
char resStar='0';
if(x<0) resStar='-';
x=abs(x);
int temp=0;
int res=0;
while(x!=0){
temp=x%10;
x=x/10;
res=res*10+temp;
if(res>214748364){
return 0;
}
}
if(resStar=='-'){
return -res;
}else{
return res;
}
}
};
给你一个字符串 s
,找到 s
中最长的回文子串。
对于一个子串而言,如果它是回文串,并且长度大于2,那么将它首尾的两个字母去除之后,它仍然是个回文串。例如对于字符串“ababa”,如果我们已经知道“bab”是回文串,那么“ababa”一定是回文串,这是因为它的首尾两个字母都是“a”。
根据这样的思路,我们就可以用动态规划的方法解决本题。我们用P(i,j)表示字符串s的第i到j个字母组成的串 (下文表示成s[i:j])是否为回文串:P(i,j)一false,其它情况这里的「其它情况」包含两种可能性:. s[i,j]本身不是一个回文串;或者 i> j,此时s[i,j]本身不合法。
那么我们就可以写出动态规划的状态转移方程:
P(i,j)=P(i+1,j- 1)乘以(S:== S;)
也就是说,只有s[i+1 :j-1]是回文串,并且s 的第i和j个字母相同时,s[i :j才会是回文串。上文的所有讨论是建立在子串长度大于2的前提之上的,我们还需要考虑动态规划中的边界条件,即子串的长度为1或2。对于长度为1的子串,它显然是个回文串;对于长度为2的子串,只要它的两个字母相同,它就是一个回文串。因此我们就可以写出动态规划的边界条件:
P(i,i)= true
P(i,i+1)=(S== Si+1)
根据这个思路,我们就可以完成动态规划了,最终的答案即为所有P(i,j)= true中j-i+1(即子串长度)的最大值。注意:在状态转移方程中,我们是从长度较短的字符串向长度较长的字符串进行转移的,因此一定要注意动态规划的循环顺序。
#include
using namespace std;
#define N 10001
int main()
{
int dp[N][N];
string s;
cin>>s;
if(s.size()<2){
//则本身为回文串;
}
int n=s.size();
int maxlen=1;
int begin=0;
// dp[i][j] 表示 s[i..j] 是否是回文串
// 初始化:所有长度为 1 的子串都是回文串
for (int i = 0; i < n; i++) {
dp[i][i] = 1;
}
// 递推开始
// 先枚举子串长度
for(int L=2;L<=n;L++){
for(int i=0;i=n){
break;
}
if(s[i]!=s[j]){
dp[i][j]=0;
}else{
if(j-i<3){
dp[i][j]=1;
}else{
dp[i][j]=dp[i+1][j-1];
}
}
// 只要 dp[i][L] == true 成立,就表示子串 s[i..L] 是回文,此时记录回文长度和起始位置
if (dp[i][j] && j - i + 1 > maxLen) {
maxLen = j - i + 1;
begin = i;
}
}
}
return 0;
}
每个位置能够存储的水的量为两步:先找左边的墙的最高的高度h1,再找右边的墙的最高的高度h2;然后计算min(h1,h2)-height;
int trap(vector& height)
{
int ans = 0;
int size = height.size();
//0位置和size-1位置都不行;
for (int i = 1; i < size - 1; i++) {
int max_left = 0, max_right = 0;
for (int j = i; j >= 0; j--) { //Search the left part for max bar size
max_left = max(max_left, height[j]);
}
for (int j = i; j < size; j++) { //Search the right part for max bar size
max_right = max(max_right, height[j]);
}
ans += min(max_left, max_right) - height[i];
}
return ans;
}
#include
using namespace std;
#define N 10001
string s;
int check(int x){
int count=0;
for(auto i:s){
if(i-'0'==x)count++;
}
return count;
}
int main()
{
cin>>s;
int flag=0;
for(int i=0;i
//在一串字符单词中比如:messages = ["Wonderful day Alice"],
//那么如何统计单词的个数,:即只需要统计空格的数量+1;
思路及算法
计算每个城市的出现次数,排序后,次数多的分配当前最大的值
这里直接加到大根堆中弹出,效果与排序一致
#include
using namespace std;
#define inf 0x3f3f3f3f
#define N 100100
int n,m,t,k,d;
int x,y,z;
char ch;
string s;
vectorv[N];
int main()
{
vectorcount;
for(int i=0;i<3;i++){
cin>>x;
count.push_back(x);
}
int ans=0;
//进行贪心:每次装入需求最多的两杯:
while(count[0]!=0||count[1]!=0||count[2]!=0){
sort(count.begin(),count.end());
if(count[2]>0)count[2]--;
if(count[1]>0)count[1]--;
ans++;
}
cout<
//对于N要进行适应性的更改,对于字段错误
#include
using namespace std;
#define inf 0x3f3f3f3f
#define N 100100
long long n,m,k,g,d,t;
int x,y,z;
char ch;
string str;
vectorv[N];
int main() {
vectornums;
setsc;
for(auto p:nums)sc.insert(p);
int res=0;
for(auto p:sc){
if(p>0)res++;
}
cout<
//对于N要进行适应性的更改,对于字段错误
#include
using namespace std;
#define inf 0x3f3f3f3f
#define N 100100
long long n,m,k,g,d,t;
int x,y,z;
char ch;
string str;
vectorv[N];
int main() {
sort(grades.begin(),grades.end());
int res=0;
int num=grades.size();
for(int i=1; ;i++){
if(num>=i){
res++;
num=num-i;
}else{
break;
}
}
return res;
return 0;
}
最短路径问题:
「最短路径」算法有 最短路径-Dijkstra 和 无权值最短路径算法(BFS)
「Dijkstra」适用于加权有向图,没有负权重边,且无环,一般是求起点到其它所有点的最短路径,也可以改进为求两点的最短路径
「无权值最短路径算法(BFS)」适用于无权有向图,可以有环,一般是求两点的最短路径,也可以改进为求起点到其它所有点的最短路径
对于本题,每条边的权重均为 1,所以可以看作为无权值,我们使用上述的第二种方法「无权值最短路径算法(BFS)」
由于点与点之间最多只有一条边,所以可以简化「无权值最短路径算法(BFS)」
public int closestMeetingNode(int[] edges, int node1, int node2) {
int n = edges.length;
// 点 node1 和 node2 到其它所有点的最短路径
int[] dist1 = getDist(edges, node1);
int[] dist2 = getDist(edges, node2);
int ans = -1, min = (int) 1e5 + 7;
// 遍历可选择的「中间点」
for (int i = 0; i < n; i++) {
// 分别为 node1 和 node2 到 i 的最短路径
int d1 = dist1[i], d2 = dist2[i];
// 如果有一方到不了,则跳过
if (d1 == -1 || d2 == -1) continue;
int max = Math.max(d1, d2);
if (max < min) {
min = max;
ans = i;
}
}
return ans;
}
// 求点 s 到其它所有点的最短路径
private int[] getDist(int[] edges, int s) {
int d = 0;
int[] dist = new int[edges.length];
Arrays.fill(dist, -1);
while (s != -1) {
// 已经访问,考虑「环」的存在
if (dist[s] != -1) break;
dist[s] = d++;
// 下一个点
s = edges[s];
}
return dist;
}
环问题:
图的最大环最长链 - Rogn - 博客园 (cnblogs.com)
这是一个模板问题、:
最长环问题:
最长链问题:
class Solution {
public:
vector> largestLocal(vector>& grid) {
vector>res;
vectorans;
int n=grid.size();
int m=grid[0].size();
int len=n-3+1;
//以 多少个位置为左上角的起点构成3*3矩阵
// 每一行
for(int i=0;i
class Solution {
public:
int edgeScore(vector& edges) {
int n=edges.size();
long long sum[n];
memset(sum,0,sizeof(sum));
for(int i=0;imax){
max=sum[i];
loc=i;
}
}
return loc;
}
};
// 蛀牙是进行 字符字母 与数字的转化;和
ch='a';
char cc = ch+1;
cout<& distance) {
setsc;
for(auto i:s)sc.insert(i);
for(auto i:sc){
int num=0;
for(int j=0;j
//对于N要进行适应性的更改,对于字段错误
#include
using namespace std;
#define inf 0x3f3f3f3f
#define N 100100
int n,m,k,g,d;
int x,y,z,t;
char ch;
string str;
vectorv[N];
long long mod = 1000000000+7;
long long sum = 0;
int endstop;
void dfs(int index,int citime,long long &sum){
if(citime>x>>endstop;
cin>>k;
dfs(x,0,sum);
cout<
滑动窗口:
res = max(res, right - left +1 ); 这个是关键;res记录过去(因为只是要结果。
class Solution {
public:
int longestNiceSubarray(vector& nums) {
int n = nums.size();
if(n == 1)return 1;
int res = 1;
int left = 0;//记录当前优雅子数组
for(int right = 1;right < n;++i){
for(int i = right - 1;i >= left;--i){
if(nums[right] & nums[i]){
//说明right指向的位置和i不可以构成优雅子数组
left = i + 1;
break;
}
}
res = max(res,right - left + 1);
}
return res;
}
};
作者:sdy-r
链接:https://leetcode.cn/problems/longest-nice-subarray/solution/by-sdy-r-glyh/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
1.使用sort函数,重写排序规则。
struct node{
int x;
int y;
}a[10];
bool cmp(node a, node b)
{
return a.x > b.x; //从大到小排列
// return a.x < b.x; 从小到大排列
}
2.在结构体中自定义排序,重小于号
struct node{
int x;
int y;
bool operator<(const node &a) const{
return x < a.x; //从大到小排序
// x > a.x; //从小到大排序
}
//这里的排序是根据每个结构体内部的x进行排序
}a[10];
3、优先队列排序(priority_queue)的使用:
结构体排序 + 优先队列排序(priority_queue)
// 优先级队列问题。
很经典的题目
很经典
线段树知识。。
class Solution {
public:
vector sortPeople(vector& names, vector& heights) {
vectorpos;
vectorheightssss;
heightssss = heights;
sort(heights.begin(),heights.end());
int n =heights.size();
for(int i=n-1;i>=0;i--){
for(int j=0;jnameee;
for(int i=0;i
按位与最大的最长子数组
好路径的数目
#include
using namespace std;
#define N 100100
#define inf 0x3f3f3f3f
int x,y,z;
int n,m,s,d,k;
string str;
char ch;
vectorv[N];
int main()
{
cin>>n;
vectorans;
while(n!=0){
ans.push_back(n%2);
n=n/2;
}
for(int i=ans.size()-1;i>=0;i--){
cout<
class Solution {
public:
int lengthOfLongestSubstring(string s) {
mapmp;
int n=s.size();
int res=0;
int right=0,left=0;
int flag=0;
for(;right
class Solution {
public:
bool isValid(string s) {
bool flag = true;
int n=s.size();
if(n%2!=0)return false;
stacks1,s2;
for(int i=0;i
【动画模拟】一文秒杀七道题 - 连续的子数组和 - 力扣(LeetCode)
要想着变化方程式,,比如哈希表的那个 pre[i] - pre[j-1] = k 变化为 pre[i] - k ; 找存在。
滑动窗口是什么呢? 可能是 一个start指针,一个end指针,进而进行滑动,根据一些题目条件进行移动。。
《挑战程序设计竞赛》这本书中把滑动窗口叫做「虫取法」,我觉得非常生动形象。因为滑动窗口的两个指针移动的过程和虫子爬动的过程非常像:前脚不动,把后脚移动过来;后脚不动,把前脚向前移动。
我分享一个滑动窗口的模板,能解决大多数的滑动窗口问题:
def findSubArray(nums):
N = len(nums) # 数组/字符串长度
left, right = 0, 0 # 双指针,表示当前遍历的区间[left, right],闭区间
sums = 0 # 用于统计 子数组/子区间 是否有效,根据题目可能会改成求和/计数
res = 0 # 保存最大的满足题目要求的 子数组/子串 长度
while right < N: # 当右边的指针没有搜索到 数组/字符串 的结尾
sums += nums[right] # 增加当前右边指针的数字/字符的求和/计数
while 区间[left, right]不符合题意: # 此时需要一直移动左指针,直至找到一个符合题意的区间
sums -= nums[left] # 移动左指针前需要从counter中减少left位置字符的求和/计数
left += 1 # 真正的移动左指针,注意不能跟上面一行代码写反
# 到 while 结束时,我们找到了一个符合题意要求的 子数组/子串
res = max(res, right - left + 1) # 需要更新结果
right += 1 # 移动右指针,去探索新的区间
return res
滑动窗口中用到了左右两个指针,它们移动的思路是:以右指针作为驱动,拖着左指针向前走。右指针每次只移动一步,而左指针在内部 while 循环中每次可能移动多步。右指针是主动前移,探索未知的新区域;左指针是被迫移动,负责寻找满足题意的区间。
模板的整体思想是:
定义两个指针 left
和 right
分别指向区间的开头和结尾,注意是闭区间;定义 sums
用来统计该区间内的各个字符出现次数;
第一重 while
循环是为了判断 right
指针的位置是否超出了数组边界;当 right
每次到了新位置,需要增加 right
指针的求和/计数;
第二重 while 循环是让 left 指针向右移动到 [left, right] 区间符合题意的位置;当 left 每次移动到了新位置,需要减少 left 指针的求和/计数;
在第二重 while 循环之后,成功找到了一个符合题意的 [left, right] 区间,题目要求最大的区间长度,因此更新 res 为 max(res, 当前区间的长度) 。
right
指针每次向右移动一步,开始探索新的区间。
模板中的 sums 需要根据题目意思具体去修改,本题是求和题目因此把sums 定义成整数用于求和;如果是计数题目,就需要改成字典用于计数。当左右指针发生变化的时候,都需要更新 sums
class Solution {
public:
int minSubArrayLen(int s, vector& nums) {
int n = nums.size();
if (n == 0) {
return 0;
}
int ans = INT_MAX;
int start = 0, end = 0;
int sum = 0;
while (end < n) {
sum += nums[end];
while (sum >= s) {
ans = min(ans, end - start + 1);
sum -= nums[start];
start++;
}
end++;
}
return ans == INT_MAX ? 0 : ans;
}
};
class Solution {
public:
vector productExceptSelf(vector& nums) {
int n=nums.size();
int sumq[n];
int sumh[n];
for(int i=0;i=0;i--){
if(i==n-1)sumh[i]=nums[i];
else sumh[i]=sumh[i+1]*nums[i];
}
vectorans;
ans.push_back(sumh[1]);
for(int i=1;i
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oGuEapDr-1679671888186)(D:/Typora/images/image-20221020153751247.png)]
class Solution {
public:
int longestOnes(vector& nums, int k) {
int n=nums.size();
int left = 0,right=0,sum=0;
int res=0;
for( ;rightk){
if(nums[left]==0)sum--;
left++;
}
res=max(res,right-left+1);
}
return res;
}
};
// 首先尝试滑动窗口 进行 求解,,但是不行,只能通过一半。
//我一开始也以为是滑动窗口,但想这样的case:[1,2,3,9,9,9,9,9];类似这样的滑窗做不了
class Solution {
public:
int longestWPI(vector& hours) {
int n=hours.size();
int left=0,right=0,sum1=0;
int res=0;
for(;right8)sum1++;
else sum1--;
while(sum1<=0&&left<=right){
if(sum1<=0&&left==right)break;
if(hours[left]>8)sum1--;
else sum1++;
left++;
}
res=max(res,right-left+1);
}
return res;
}
};
// 下面的有点偏暴力了
class Solution {
public:
int longestWPI(vector& hours) {
int n=hours.size();
int sum[n];
int nums[n];
for(int i=0;i8)nums[i]=1;
else nums[i]=-1;
}
sum[0]=nums[0];
for(int i=1;i0){ //特别是这个判断条件的 +nums[i]
res=max(res,j-i+1);
}
}
}
return res;
}
};
class Solution {
public:
int pivotIndex(vector& nums) {
int n=nums.size();
int sum[n+1];
sum[0]=0;
for(int i=0;ians;
for(int i=1;i<=n;i++){
int left = sum[i-1];
int right = sum[n]-sum[i];
if(left==right){
ans.push_back(i-1);
}
}
if(ans.size()==0)return -1;
else return ans[0];
}
};
思路:其实我们现在这个题目和两数之和原理是一致的,只不过我们是将所有的前缀和该前缀和出现的次数存到了 map 里。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ikxzAXnr-1679671888186)(D:/Typora/images/image-20221025191243786.png)]
class Solution {
public:
int subarraySum(vector& nums, int k) {
mapmp;
mp[0]=1;//是从开始到自身即pre[i]-k=0;即
int n=nums.size();
int pre[n+1];
pre[0]=0;
int res=0;
for(int i=1;i<=n;i++){
pre[i]=pre[i-1]+nums[i-1];
if(mp.find(pre[i]-k)!=mp.end()){
res+=mp[pre[i]-k];
}
mp[pre[i]]++;
}
return res;
}
};
思路”要想着变化方程式;;;
class Solution {
public:
int numberOfSubarrays(vector& nums, int k) {
int res=0;
int n=nums.size();
int pre[n+1];
pre[0]=0;
mapmp;
mp[0]=1;
for(int i=0;i
其中 巧妙的 还是 方程变化。 以及对 负数的处理。
class Solution {
public:
int subarraysDivByK(vector& nums, int k) {
mapmp;
mp[0]=1;
int n=nums.size();
int pre[n+1];
pre[0]=0;
int res=0;
for(int i=1;i<=n;i++){
// 注意负数 的问题。
pre[i]=pre[i-1]+nums[i-1];
if(mp.find((pre[i]%k+k)%k)!=mp.end()){
res+=mp[(pre[i]%k+k)%k];
}
mp[(pre[i]%k+k)%k]++;
}
return res;
}
};
class Solution {
public:
bool checkSubarraySum(vector& nums, int k) {
int n = nums.size();
mapmp;
mp[0]=1;
int pre[n+1];
pre[0]=0;
int res = 0;
pre[1]=pre[0]+nums[0];
for(int i=2;i<=n;i++){
pre[i]=pre[i-1]+nums[i-1];
if(mp.find(pre[i]%k)!=mp.end()){
res+=mp[pre[i]%k];
}
mp[pre[i-1]%k]++; // 因为个数限制。
}
if(res==0)return false;
else return true;
}
};
class Solution {
public:
int numSubarraysWithSum(vector& nums, int goal) {
mapmp;
mp[0]=1;
int n=nums.size();
int pre[n+1];
pre[0]=0;
int res=0;
for(int i=1;i<=n;i++){
pre[i]=pre[i-1]+nums[i-1];
if(mp.find(pre[i]-goal)!=mp.end()){
res+=mp[pre[i]-goal];
}
mp[pre[i]]++;
}
return res;
}
};
class Solution {
public:
int totalFruit(vector& fruits) {
int res = 0;
int n =fruits.size();
int right=0,left=0;
setsc;
mapmp;
for(;right2){
mp[fruits[left]]--;
if(mp[fruits[left]]==0)sc.erase(fruits[left]);
left++;
}
res=max(res,right-left+1);
}
return res;
}
};
1]=pre[0]+nums[0];
for(int i=2;i<=n;i++){
pre[i]=pre[i-1]+nums[i-1];
if(mp.find(pre[i]%k)!=mp.end()){
res+=mp[pre[i]%k];
}
mp[pre[i-1]%k]++; // 因为个数限制。
}
if(res==0)return false;
else return true;
}
};
## [930. 和相同的二元子数组](https://leetcode.cn/problems/binary-subarrays-with-sum/):前缀和+哈希表
```c++
class Solution {
public:
int numSubarraysWithSum(vector& nums, int goal) {
mapmp;
mp[0]=1;
int n=nums.size();
int pre[n+1];
pre[0]=0;
int res=0;
for(int i=1;i<=n;i++){
pre[i]=pre[i-1]+nums[i-1];
if(mp.find(pre[i]-goal)!=mp.end()){
res+=mp[pre[i]-goal];
}
mp[pre[i]]++;
}
return res;
}
};
class Solution {
public:
int totalFruit(vector& fruits) {
int res = 0;
int n =fruits.size();
int right=0,left=0;
setsc;
mapmp;
for(;right2){
mp[fruits[left]]--;
if(mp[fruits[left]]==0)sc.erase(fruits[left]);
left++;
}
res=max(res,right-left+1);
}
return res;
}
};