基础算法复习 (上午)

双指针

一本书P页,第i页有知识点ai,同一个知识点可能多次提到,希望通过连续的一些页把所有知识点都覆盖到。求出连续的最少页数

#include <iostream>
#include <algorithm>
#include <cmath>
#include <set>
#include <map>
#include <cstdio>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=1e6+10;

int a[maxn];
int n;
set <int> s; 
map <int,int> vis;
int main() {

	//ios::sync_with_stdio(0);
	//cin.tie(0);
	scanf("%d",&n);
	for (int i=0; i<n; i++) {
		scanf("%d",&a[i]);
		s.insert(a[i]);
	}
	int len=s.size();
	int l=0,r=0,cnt=0;
	int ans=n; 
	while (1){
		while (r<n && cnt<len){
			if (vis[a[r]]==0)							
				cnt++;			
			vis[a[r]]++;
			r++;
		}
		if (cnt<len) break;
		ans=min(ans,r-l);
		vis[a[l]]--;
		if (vis[a[l++]]==0)
			cnt--;
	}
	printf("%d\n",ans);
	return 0;
}

盛水问题

距离单调递减,所以我们保证长度较小的先去掉
image
image

去重元素,空间o1

删除数组nums 中的重复元素,使每个元素只出现一次。并输出去除重复元素之后数组的长度。
题解:
image

分离指针

分离双指针一般用于处理有序数组合并,求交集、并集问题。
image

三数之和

枚举i的位置,jz两个指针
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        int n=nums.size();
        vector<vector<int>> res;
        sort(nums.begin(),nums.end());
        for (int i=0;i<n;i++)
        {
            //当前项和前一项相同,则当前数字已经被刚才用过了,则直接跳过这个数字
            if (i>0 && nums[i]==nums[i-1])
            {
                continue;
            }
            //第二重循环同时遍历 j 和 z
            int z=n-1;  //初始化z的位置,z从后往前
            for (int j=i+1;j<n;j++)   //j从前往后
            {
                //同理,跳过重复的数字
                if (j>i+1 && nums[j]==nums[j-1])
                {
                    continue;
                }
                //同时需要保证j<z:因为j作为左指针一定要在z右指针的左边
                while (j<z && nums[i]+nums[j]+nums[z]>0)
                {
                    //因为序列从小到大排序,当前的结果大于0,则减小z,寻找合适的位置
                    --z;
                }
                //如果j 和 z相遇,则表示无论j再往后,z再往前,他们都不可能再有结果了(和为0),因为j再往后遍历的数字一定和z之前的一个数字相同; z也是,一定和j之前的一个数字相同,我们已经遍历过了,所以这种情况直接退出 
                if (j==z)
                {
                    break;
                }
                if (nums[i]+nums[j]+nums[z]==0)
                {
                    res.push_back({nums[i],nums[j],nums[z]});
                }
            }
        }
        return res;
    }
};

回文串问题

https://www.cnblogs.com/jiamian/p/11252214.html
https://blog.csdn.net/m0_74922218/article/details/136886949
(动态规划版)
image


算法竞赛书 二分 (下午)

函数补充

**lower_bound **

lower_bound(vec.begin(), vec.end(), 4)

upper_bound

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> vec = {1, 2, 4, 4, 5, 6};

    int x = 4;

    // 查找第一个不小于 x 的元素
    auto lb = std::lower_bound(vec.begin(), vec.end(), x);
    std::cout << "Index of the first element not less than " << x << ": " << (lb - vec.begin()) << std::endl;
    std::cout << "Value at this index: " << *lb << std::endl;

    // 查找第一个大于 x 的元素
    auto ub = std::upper_bound(vec.begin(), vec.end(), x);
    std::cout << "Index of the first element greater than " << x << ": " << (ub - vec.begin()) << std::endl;
    std::cout << "Value at this index: " << (ub == vec.end() ? "end" : std::to_string(*ub)) << std::endl;

    return 0;
}
//输出 4 2 4
       4 4 5

equal_range

返回第一个不小于给定值的迭代器,又返回第一个大于给定值的迭代器
image
**find **

在容器中查找第一个等于给定值的元素,并返回指向该元素的迭代器。如果没有找到,返回指向容器末尾的迭代器。
**binary_search **

binary_search(vec.begin(), vec.end(), 4);找不到返回false

用于检查元素是否存在于排序数组中

std::sort(vec.begin(), vec.end()); // 排序
std::reverse(vec.begin(), vec.end()); // 逆序

find_if

#include <algorithm>  // std::find_if
#include <vector>

std::vector<int> vec = {1, 2, 4, 4, 5, 7};
auto it = std::find_if(vec.begin(), vec.end(), [](int x) { return x > 4; });
// 查找第一个大于4的元素

二分

子数组最小值最大

(动态规划版)
动态规划

最大值最小化
有序列{2,2,3,4,5,1},划分为3个连续的子序列,子序列的和最大值最小
如(2,2,3),(4),(5,1)最大值最小为7

用二分法记录最大的值和在序列中最大的值3,而最大值最小一定在这里面。
(有点类似跳石头,跳石头枚举最小距离,最这个最小距离能否由拿走n块石头实现,这里枚举的使子序列和的最小值,看这样的最小值能不能在划分三次时成立)
类似的,划分数组为n个时,数组和的最大值(最小值最大)
csdn

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 7;
int n, m;
int a[maxn];
int check(int x) {
	int cnt = 1;
	int s = a[1];
	for (int i = 2; i <= n; i++) {
		if (s + a[i] <= x) s += a[i];
		else { s = a[i]; cnt++; }
	}
	return cnt;
}
int bin_search(int l, int r) {
	while (l < r) {
		int mid = l + (r - l) / 2;
		if (check(mid) <= m) {
			r = mid;
		}
		else {
			l = mid + 1;
		}
	}
	return l;
}
int main() {
	int t;
	ll mx, sum;
	cin >> t;
	while (t--) {
		mx = 0, sum = 0;
		cin >> n >> m;
		for (int i = 1; i <= n; i++) {
			cin >> a[i];
			sum += a[i];
			if (mx < a[i])
				mx = a[i];
		}
		int ans = bin_search(mx, sum);
 
		cout << ans;
	}
	return 0;
}

琐碎(下午)

洛谷模拟例题

image
运用ASCII码

#include<cstdio>
using namespace std;
int a[3];char s1,s2;
int main()
{
    while (scanf("%c:=%c;",&s1,&s2)==2)//充分利用c++语言优势
     a[s1-'a']=s2>='0' && s2<='9' ? s2-'0' : a[s2-'a']; //赋值语句简洁明了
    printf("%d %d %d",a[0],a[1],a[2]);
}

运用map

 #include<iostream>
    #include<map>//Map头文件
    #include<cstdio>
    using namespace std;
    map <char,int> num;//表示以char类型为下标,存储的是int
    string st;
    int main(){
        cin>>st;//输入
        int len=st.length();
        num['a']=num['b']=num['c']='0';//注意初始化。。。。被坑了
        for(int i=0;i<len;i+=5)
          if(st[i+3]>='0'&&st[i+3]<='9')//注意判断是不是0~9
            num[st[i]]=st[i+3];//直接取出数字赋值给对应变量
           else num[st[i]]=num[st[i+3]];//变量之间相赋值
        printf("%c %c %c",num['a'],num['b'],num['c']);
        //输出三个变量
        return 0;
    }

技巧

为了防止多组测试,直接

while(cin>>n);

const long double pi=acosl(-1.0);//圆周率

sinl(),cosl()//三角函数的long double 版本
sinf//float版本
sin()//double

cout<<fixed<<serprecision(6);

头文件

#include<iostream>
#include<algorithm>//数学
#include<cstdio>
#include<cstring>
#include<cmath>//数学
#include<cctype>
#include<iomanip>
#include<map>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<set>
#include<cctype>
#include<string>
#include<stdexcept>
#include<fstream>

vj团队赛2 (补题)

求最大公约数

有一个整数 n,1-n个数字分成两组,每一组至少有一个数,并且使得两组数字的和的最大公约数最大,请输出最大的最大公约数。
image
(即gcd a,b是sum的因子)

#include <iostream>   
#include <cstdio>    
#include <iomanip>
#define int long long
using namespace std;
const int N=1e5+10;
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int n;
    cin>>n;
    int sum=n*(n+1)/2;
    for(int i=2;i<=n/2;i++){
        if(sum%i==0) 
        {
            cout<<sum/i<<endl;
            break;
        }
    }
    return 0;
}

七巧板

第一次6,第二次7...规律
int t=7+(6+n-1+6)*n/2;

圆内面积最大值

image

最小函数值

看不懂
https://blog.51cto.com/u_15357029/5098564
https://blog.csdn.net/u011815404/article/details/80657563

钟表问题

(暴力可过)

//还是要手动模拟一下,就知道怎么枚举了

image

(暴力超时)(但是还是不懂怎么暴力

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const double INF = 1e9;

// 将时间转换为秒
int time_to_seconds(int h, int m, int s) {
    return h * 3600 + m * 60 + s;
}

// 计算从时间a到时间b的顺时针角度
double calculate_cw_angle(int a, int b) {
    int diff = (b - a + 43200) % 43200; // 计算顺时针角度
    return diff * 360.0 / 43200; // 计算角度
}

// 计算从时间a到时间b的逆时针角度
double calculate_ccw_angle(int a, int b) {
    int diff = (a - b + 43200) % 43200; // 计算逆时针角度
    return diff * 360.0 / 43200; // 计算角度
}

int main() {
    int n;
    cin >> n;

    vector<int> times(n + 1); // 用来存储时间的秒数,包含当前时间和所有目标时间
    int h, m, s;

    cin >> h >> m >> s;
    int start_time = time_to_seconds(h % 12, m, s); // 将当前时间转化为秒

    times[0] = start_time;

    for (int i = 1; i <= n; ++i) {
        cin >> h >> m >> s;
        int time_point = time_to_seconds(h % 12, m, s); // 将目标时间转化为秒
        times[i] = time_point;
    }

    double min_angle = INF;

    // 枚举所有时间点的排列
    vector<int> perm(n);
    iota(perm.begin(), perm.end(), 1); // 排列从1到n的索引

    do {
        double total_angle = 0;
        int current_time = start_time;

        for (int i : perm) {
            total_angle += calculate_cw_angle(current_time, times[i]);
            current_time = times[i];
        }

        total_angle += calculate_cw_angle(current_time, start_time); // 返回到起点
        min_angle = min(min_angle, total_angle);

    } while (next_permutation(perm.begin(), perm.end()));

    // 输出结果,保留两位小数
    printf("%.2f\n", min_angle);
    return 0;
}

补充 next_permutation

image
image

posted on 2024-07-23 20:46  Hoshino1  阅读(2)  评论(0编辑  收藏  举报