首页 > 其他分享 >双指针具有单调性

双指针具有单调性

时间:2024-03-10 22:33:55浏览次数:16  
标签:int long 具有 https ans 指针 单调 define

双指针的题目往往是看起来需要O(n),我们一般枚举一个指针,然后我们发现另一个指针不走回头路,不论是哪个方向,这样我们的时间复杂度就是O(n).
从例题来看:

给定一个字符串,我们希望找到最短长度区间能包含所有字母类型。

核心:对于左端点固定的时候,我们找到最小的r,然后我们考虑i右移动一位,这时候我们的j是一定不会回头的,因为不回头,都已经少了一个字母且当前假设已经不包含所有字母了,。

所以i和j都是单调移动的
https://codeforces.com/contest/701/problem/C

// Problem: C. They Are Everywhere
// Contest: Codeforces - Codeforces Round 364 (Div. 2)
// URL: https://codeforces.com/problemset/problem/701/C
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;
#define ll long long
//# define int long long
#define ull unsigned long long
#define pii pair<int,int>

#define baoliu(x, y) cout << fixed << setprecision(y) << x
#define endl  "\n"
#define debug1(x) cerr<<x<<" "
#define  debug2(x) cerr<<x<<endl
const int N = 2e5 + 10;
const int M = 1e6 + 10;
const int inf = 0x3f3f3f3f;
const int mod = 998244353;
const double eps = 1e-8;
int n, m;
int a[N];

void solve(){
	cin>>n;
	string str;cin>>str;
	set<int>s;
	for(int i=0;i<n;i++){
		s.insert(str[i]);
	}
	int m=s.size();
	map<char,int >ans;int res=inf;
	int j=0;
	for(int i=0;i<n;i++){
		while(j<n&&ans.size()<m){
			ans[str[j]]++;
			j++;
			}
			//cerr<<i<<" "<<j<<endl;
		if(ans.size()==m)res=min(res,j-i);
		ans[str[i]]--;
		if(ans[str[i]]==0)ans.erase(str[i]);
	}
	cout<<res;
}
int main() {
    cin.tie(0);
    
    ios::sync_with_stdio(false);

    int t;
   //cin>>t;
     t=1;
    while (t--) {
solve();
    }
    return 0;
}

例题2

https://ac.nowcoder.com/acm/problem/269221

题意:需要在有序数组中找到最长区间满足区间极差小于等于m

做法:我们考虑枚举左端点,那么当左端点增大,右端点一定只能不动或者向右移动

  • 所以也可以双指针解决
void solve(){
	cin>>n>>m;
	for(int i=1;i<=n;i++)cin>>a[i];
	int ans=-1;
	sort(a+1,a+n+1);int j=1;
	//for(int i=1;i<=n;i++)cerr<<a[i]<<" ";
	//cerr<<endl;
	for(int i=1;i<=n;i++){
		while(j+1<=n&&a[j+1]-a[i]<=m)j++;
		//cerr<<i<<" "<<j<<endl;
		ans=max(ans,j-i+1);
	}
	double res=1.0*ans/(double)n;
	baoliu(res,6);
}

本题为easy版本,和hard版本的唯一区别是\(a_i\)保证是正整数****!

小红拿到了一个数组,她想知道,有多少非空区间满足区间所有元素之和不小于\(k\)?

由于这个版本a[i]都是正整数,我们直接前缀和转化以后,等价于前缀和数组视角下的上一题

void solve(){
	int k;cin>>n>>k;
	for(int i=1;i<=n;i++)cin>>a[i];
int j=1;
int ans=0;
for(int i=1;i<=n;i++)s[i]=s[i-1]+a[i];
for(int i=1;i<=n;i++){
	while(j<=n&&s[j]-s[i-1]<k)j++;
	//cerr<<i<<" "<<j<<endl;
	ans+=n-j+1;
	
}
cout<<ans;
}

hard版本:带负数情况

  • 我们需要找到大于a[i]+k的数a[j]且j>i.
  • 由于存在负环没有单调性,我们只能用解决逆序对的方法:离散化权值树状数组
  • 我们要求的是后缀,所以还要倒着求,我们枚举的是左端点

离散化过程明显不熟,下次看到的时候一定要刻意练习

// Problem: 小红统计区间(hard)
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/73239/F
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;
#define ll long long
# define int long long
#define ull unsigned long long
#define pii pair<int,int>

#define baoliu(x, y) cout << fixed << setprecision(y) << x
#define endl  "\n"
#define debug1(x) cerr<<x<<" "
#define  debug2(x) cerr<<x<<endl
const int N = 2e5 + 10;
const int M = 1e6 + 10;
const int inf = 0x3f3f3f3f;
const int mod = 998244353;
const double eps = 1e-8;
int n, m;
int a[N];
vector<int>lan;
template <typename T>
struct Fenwick {
    int n;
    std::vector<T> a;
    
    Fenwick(int n_ = 0) {
        init(n_);
    }
    
    void init(int n_) {
        n = n_;
        a.assign(n, T{});
/*
T{}是一种初始化T类型对象的方式,它使用了花括号初始化列表进行数值初始化。
对于大多数内置数据类型(如整数、浮点数),这将初始化为0。
*/

    }
    
    void add(int x, const T &v) {
        for (int i = x; i <=n-1; i += i & -i) {
            a[i] = a[i] + v;
        }
    }
    
    T sum(int x) {
        T ans{};
        for (int i = x; i > 0; i -= i & -i) {
            ans = ans + a[i];
        }
        return ans;
    }
    
    T rangeSum(int l, int r) {//要传入l-1
    //待优化:直接给个vector记录前缀和
        return sum(r) - sum(l);
    }
    
    int select(const T &k) {//寻找最后一个使得前缀和小于等于 k 的位置。
        int x = 0;
        T cur{};
        for (int i = 1 << std::__lg(n-1); i; i /= 2) {//GCC
            if (x + i <= n-1 && cur + a[x + i] <= k) {
                x += i;
                cur = cur + a[x];
            }
        }
        return x;
    }
};

void discrete()
{
    sort(lan.begin(), lan.end());   //排序
    lan.erase(unique(lan.begin(), lan.end()), lan.end());   //去重
}

//查询
int find(int x)
{
 return lower_bound(lan.begin(), lan.end(), x)-lan.begin()+1;  //返回所查询的数据的下标
}
void solve(){
	int k;cin>>n>>k;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		a[i]+=a[i-1];
		lan.push_back(a[i]);
	}
	Fenwick<int>c(n+1);
	discrete();
	//for(auto x:lan)cerr<<x<<" ";
	//cerr<<endl;
	int ans=0;
	int tt=find(a[n]);
	c.add(tt,1);
	for(int i=n-1;i>=0;i--){
		int pos=1;
	 pos=find(a[i]+k);
	// cerr<<a[i]<<" "<<a[i]+k<<" "<<pos<<endl;
		if(pos!=lan.size()+1)ans+=c.rangeSum(pos-1,n);
		//cerr<<c.rangeSum(pos-1,n)<<endl;
		int tmp=find(a[i]);
		c.add(tmp,1);
	}
	cout<<ans<<endl;
}
signed main() {
    cin.tie(0);
    
    ios::sync_with_stdio(false);

    int t;
   //cin>>t;
     t=1;
    while (t--) {
solve();
    }
    return 0;
}

标签:int,long,具有,https,ans,指针,单调,define
From: https://www.cnblogs.com/mathiter/p/18064963

相关文章

  • 常量指针与指针常量
    常量指针与指针常量constint*p1;//常量指针,从后往前可以理解为:p1isapointerpointtoconstint常量指针:声明了一个指向整型常量的指针p1,不能通过这个指针p1去修改所指向变量的值。但是可以修改指针p1的指向,即指针p1可以指向别的同类型变量int*constp2;//指针常量......
  • 函数返回数组指针 看不太懂
    有三种方法1.声明一个返回数组指针的函数int(*func(inti))[10];func(inti)表示调用func函数所需要一个int类型的实参。(*func(inti))意味着我们可以对函数调用的结果执行解引操作。//意思就是函数调用的结果的是个指针。(*func(inti))[10]......
  • UE 共享指针 共享引用
    classFTestA{public: FTestA(){ UE_LOG(LogTemp,Warning,TEXT("FTestA构造")); } voidTestFun(){ UE_LOG(LogTemp,Warning,TEXT("FTestATestFun方法")); } ~FTestA(){ UE_LOG(LogTemp,Warning,TEXT("FTestA析构")); }};......
  • c/c++指针中 * 和 & 的区别与联系
    在C语言中,*和&是两个非常基础但功能相反的操作符,它们分别是解引用(dereference)操作符和取地址(address-of)操作符。&(取地址操作符)用途:&操作符用来获取变量的内存地址。示例:假设有一个整型变量intx=10;,则&x表示获取变量x的内存地址。如果你有一个指针变量想要存储变量x的地址,可......
  • CUDA指针数组Kernel函数
    技术背景在前面的一篇文章中,我们介绍了在C++中使用指针数组的方式实现的一个不规则的二维数组。那么如果我们希望可以在CUDA中也能够使用到这种类似形式的不规则的数组,有没有办法可以直接实现呢?可能过程会稍微有一点麻烦,因为我们需要在Host和Device之间来回的转换,需要使用到很多C......
  • this指针的使用
    c++提供特殊的对象指针,也就是this指针,this指针指向被调用的成员函数所属的对象this指针是隐含每一个非静态成员函数内的一种指针this函数不需要定义,直接使用即可 this指针的用途:当形参和成员变量同名时,可用this指针来区分在类的非静态成员函数中返回对象本身,可使用return......
  • leetcode-15. 三数之和 - 双指针问题
    classSolution:defthreeSum(self,nums:List[int])->List[List[int]]:nums.sort()res=[]mem=set()foriinrange(len(nums)):ifnums[i]>0:breakifi>0andnum......
  • leetcode--901. 股票价格跨度(单调栈)
    记录10:002024-3-6https://leetcode.cn/problems/online-stock-span/维护一个单调递减的栈s,并且也要一个记录个数的栈count每次来一个数据,这个数据如果比s栈顶数据小,就直接放入s,并在count中记录下它的个数1如果这个数据比s栈顶数据大,就需要弹出s和count的top,来保证s是递减的......
  • 代码随想录算法训练营第三十七天 | 738. 单调递增的数字,968.监控二叉树
    968.监控二叉树 已解答困难 相关标签相关企业 给定一个二叉树,我们在树的节点上安装摄像头。节点上的每个摄影头都可以监视其父对象、自身及其直接子对象。计算监控树的所有节点所需的最小摄像头数量。 示例1:输入:[0,0,null,0,0]输出:1......
  • 【洛谷】明明的随机数(双指针去除重复元素)
    题目描述代码:#include<iostream>#include<algorithm>usingnamespacestd;intmain(){ intn; cin>>n; intA[n]; for(inti=0;i<n;i++){ cin>>A[i]; } sort(A,A+n); intslow=0,fast=0; while(fast<n){ if(slow!=......