PAT之查找:遍历、二分、hash

知识点笔记:哈希存储:字符串存储、数字存储

1 遍历

2 二分

模板

// 相等
int find_equ(int low, int high, int a[], int key){
	int mid;
	while(low<high){
		mid = (low+high)/2;
		if(a[mid] == key){
			return mid;		//mid
		}else if(key < a[mid]){	 //左边找
			high = mid-1;
		}else{
			low = mid+1;
		}
	}
	return -1;
}

// 第一个>=(升序)
int find_lower_bound(int low, int high, int a[], int key){
	int mid;
	while(low<high){
		mid = (low+high)/2;
		if(a[mid] >= key){  //因为a[mid]>=key,所以右边均>=key。第一个>=key的位置,在左边找[low, mid],可能在mid位置=,所以high不能为mid-1
			high = mid;
		}else{
			low = mid+1;	
		}
	}
	if(a[low]>=key) return low;		//low=high
	else return -1;		
}

// >
int find_lower(int low, int high, int a[], int key){
	int mid;
	while(low<high){
		mid = (low+high)/2;
		if(a[mid] > key){  // 左边找[low, mid], 可能在mid位置第一个>,所以high不能为mid-1
			high = mid;
		}else{
			low = mid+1;	
		}
	}
	if(a[low]>key) return low;		//low=high
	else return -1;		
}



int arr[3] = {5, 10, 15};
//  >=
int *p, index;
p = lower_bound(arr, arr+3, 20);		//不存在,返回假设存在arr[i]>=20应该在的位置,即index=3
index = p-arr;
int k = find_lower_bound(0,2,arr, 10);	//k=1
// >
p = upper_bound(arr, arr+3,15);			//不存在,返回假设存在arr[i]>15的位置,即index=3
index = p-arr;
k = find_lower(0,2,arr,10);		// k=2

1044(25:连续子序列和)

(1)题目
求所有连续子序列和>=k的子序列

(2)代码

#include<cstdio>
#include<vector>
#include<algorithm>

using namespace std;

const int N = 1e+5+10;
const int INF=0x3f3f3f3f;

typedef struct Node{
	int start;
	int end;
}Node;

// >=
int find_lower_bound(int low, int high, int a[], int key){
	int i=low;
	int mid;
	while(low<high){
		mid = (low+high)/2;
		if(a[mid]-a[i-1] >= key){
			high = mid;
		}else{
			low = mid+1;	
		}
	}
	return low;  //low=high
}

bool cmp(Node no1, Node no2){
	return no1.start < no2.start;
}



vector<int> vect;
int sum[N]={0};		//sum[i]:vect[1] 到 vect[i]的和
	
int main(){
	//freopen("in.txt", "r",stdin);

	
	int n,m;
	scanf("%d%d", &n, &m);
	vect.resize(n+1);
	for(int i=1; i<=n; i++){
		scanf("%d", &vect[i]);
		sum[i] = sum[i-1] + vect[i];
	}
	int tempSum,j;
	int minSum=INF;
	vector<Node> vect2;
	Node node;
	for(int i=1; i<vect.size(); i++){
		j = find_lower_bound(i,vect.size()-1,sum,m);	//第一个sum[j]-sum[i-1]>=m的j:即vect[i] +...+ vect[j]>=m
		tempSum = sum[j] - sum[i-1];
		if(tempSum < minSum && tempSum>=m){
			vect2.clear();
			node.start = i;
			node.end = j;
			vect2.push_back(node);
			minSum = tempSum;
		}else if(tempSum == minSum && tempSum>=m){
			node.start = i;
			node.end = j;
			vect2.push_back(node);
		}
	}
	sort(vect2.begin(), vect2.end(), cmp);
	for(int i=0; i<vect2.size(); i++){
		printf("%d-%d\n", vect2[i].start, vect2[i].end);
	}

	

	//fclose(stdin);
	return 0;
}

(3)小结

  • 连续子序列和,设置sum[N]
  • 当外层循环为10^5时,内层查找用二分,不能用遍历(超时)

3 hash

3.1 数字存储

1121(25)

题目:

(2)代码

#include<cstdio>
#include<vector>
#include<algorithm>

using namespace std;

const int ID_MAX = 100000+10;
const int N = 50000+10;

int couple[ID_MAX];  //couple[i]=j,i和j是一对couples
bool party[ID_MAX];   //party[i]:id=i   party[i]=true:出席了party
vector<int> alone;  //第1种没有couple,第2种自己的couple没出席


int main()
{
    //freopen("in.txt", "r", stdin);
    fill(couple,couple+N, -1);
    int n;
    scanf("%d", &n);
    for(int i=0; i<n; i++){
        int a, b;
        scanf("%d%d", &a,&b);
        couple[a] = b;
        couple[b] = a;
    }
    int m;
    scanf("%d", &m);
    for(int i=0; i<m; i++){
        int g;
        scanf("%d", &g);
        party[g]=true;
    }
    for(int i=0; i<ID_MAX; i++){
        if(party[i]){
            int j=couple[i];
            if(j==-1){      //没有couple
                alone.push_back(i);
            }else if(!party[j]){    //自己的couple没出席
                alone.push_back(i);
            }
        }
    }
    sort(alone.begin(), alone.end());
    printf("%d\n",alone.size());
    for(int i=0; i<alone.size(); i++){
        if(i!=0){
            printf(" ");
        }
        printf("%05d", alone[i]);
    }

    //fclose(stdin);
    return 0;
}


(3)小结

  • 一对数字:a[i] = j(i和j是一对)
  • 有时可用set,有时用hash更方便
    如:bool party[ID_MAX]或int party[ID_MAX]

3.2 字符串存储

模板

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值