力扣-5+CCF两题

题目一

在这里插入图片描述

思路

区间DP

玩DP,先确定为什么是DP,再就是老四样,先找好几个状态,赋初始值,找转移,最后找答案。

确定算法

abba是回文串,那么bb一定是回文串,所以抽象出大问题abba是不是回文串,小问题bb是不是回文串,当bb是回文串即小问题成立,并且同时左右端点一致,,则推导出大问题成立,所以可以尝试DP算法

定状态

因为是子串,所以是连续的一个子序列,所以只需要表示出这个子序列的区间就行,所以用i,j表示区间即可。

找初始值(空串或者左一个右一个的字符)

回文串必须是左右两个节点一起判断,所以初始值是单个一个字符情况和两个字符情况。

找转移

正如上面分析所示(小问题怎么推出大问题),当两端一样,大区间的结果就看小区间的,所以

				if (s[i] == s[j]) {
    
    	
					dp[i][j] = dp[i + 1][j - 1];
				}

找答案

1、这道题其实关键就在找答案上,他要的最长子串,如果这题仅仅是求最长子串长度,那么用dp[][]即可,不是回文子串的就是0,反之存长度。
2、但这题要把子串找出来,所以用substr方法,需要知道起点+长度,所以两个信息存不下,那么dp[][] 正常存bool值,起点+长度单独计。因为我们寻找顺序就是区间由小到大,并且体重要求只需要长度最大,对长度相同的不同串都允许,所以我们只要找到一个回文子串,就记录起点+长度,因为我们从小到大的找,最后一次更新后,一定是最大的,即为答案。

代码

class Solution {
    
    
public:
	string longestPalindrome(string s) {
    
    
		int n = s.size();
		int begin = 0, max_length = 0;
		bool dp[1050][1050] = {
    
     false };//初始化
		for (int i = 0; i < n; i++) {
    
    //初始化
			dp[i][i] = true;
			begin = i;//判断是回文子串就更新起点加长度
			max_length = 1;
		}
		for (int i = 0; i < n - 1; i++) {
    
    //初始化
			if (s[i] == s[i + 1]) {
    
    
				dp[i][i + 1] = true;
				begin = i;//判断是回文子串就更新起点加长度
				max_length = 2;
			}
		}
		for (int l = 2; l < n; l++) {
    
    
			for (int i = 0, j; i + l < n; i++) {
    
    
				j = i + l;
				if (s[i] == s[j]) {
    
    //当两端一样,大区间的结果就看小区间的
					if (dp[i + 1][j - 1]) {
    
    //判断是回文子串就更新起点加长度
						begin = i;
						max_length = l + 1;
					}
					dp[i][j] = dp[i + 1][j - 1];
				}
			}
		}
		return  s.substr(begin, max_length);
	}
};

(所有代码均已在力扣上运行无误)

经测试,该代码运行情况是(经过多次测试所得最短时间):

在这里插入图片描述

时间复杂度:O(N^2)
空间复杂度:O(N^2)

题目二:

在这里插入图片描述
在这里插入图片描述

思路

直接模拟题目要求,注意用STL的排序之前,要对结构体内部 operator < 进行重写

代码

//202009-1	称检测点查询

#include <iostream>
#include <algorithm>
#include <unordered_set>
using namespace std;

int n, x, y;//总点数,目标人物坐标

struct position {
    
    
	int x;
	int y;
	int id;//监测点序号
	long long distance;//距离,为防止溢出,所以开long long

	bool operator < (const position& p)const {
    
    //覆写 operator <方法,为了使用sort函数
		if (distance == p.distance) {
    
    //距离相等要编号小的
			return id < p.id;
		}
		return distance < p.distance;//先比距离,要小的
	}
};

position p[201];

int main()
{
    
    
	cin >> n >> x >> y;
	for (int i = 0; i < n; i++) {
    
    
		scanf("%d %d", &p[i].x, &p[i].y);
		p[i].id = i + 1;
		p[i].distance = (p[i].x - x)*(p[i].x - x) + (p[i].y - y)*(p[i].y - y);
	}
	sort(p, p + n);//从小到大排序
	for (int i = 0; i < 3; i++) {
    
    
		printf("%d\n", p[i].id);
	}
	return 0;
}

(所有代码均已在力扣上运行无误)

经测试,该代码运行情况是(经过多次测试所得最短时间):

在这里插入图片描述

时间复杂度:O(N)

题目三

在这里插入图片描述
在这里插入图片描述

思路:

直接模拟就行,但是注意,这里经过高风险的人数指的是一旦路过就算,而逗留指的是连续k个点都在高风险地区,二者分开统计

代码:

//202009-2	风险人群筛查

#include <iostream>
#include <algorithm>
#include <unordered_set>
using namespace std;


int n, k, t, xl, yd, xr, yu;//含义见题目


int main()
{
    
    
	int ans_linger = 0;//逗留人数-只要经过高危区域就算
	int ans_pass = 0;//途径人数
	cin >> n >> k >> t >> xl >> yd >> xr >> yu;
	for (int i = 0; i < n; i++) {
    
    //控制第i个人
		int tmp_x, tmp_y, cnt = 0;
		bool is_visited = false;//看是否经过高风险
		bool is_judged = false;//是否连续k个点在高风险
		for (int j = 0; j < t; j++) {
    
    //第i个人的第j个点(xj,yj)
			scanf("%d %d", &tmp_x, &tmp_y);
			if (tmp_x >= xl && tmp_x <= xr && tmp_y >= yd && tmp_y <= yu) {
    
    
				cnt++;
				is_visited = true;//路过即为true
				if (cnt >= k && !is_judged) {
    
    //一旦连续k个点了
					ans_linger++;
					is_judged = true;//连续k点一次即可判定为逗留,之后不在判断
				}
			}
			else {
    
    
				if (cnt) {
    
    //这里是因为不是连续k个点,不算逗留,所以要清零
					cnt = 0;
				}
			}
		}
		if (is_visited) {
    
    
			ans_pass++;
		}
	}
	printf("%d\n", ans_pass);
	printf("%d", ans_linger);
}

(所有代码均已在力扣上运行无误)

经测试,该代码运行情况是(经过多次测试所得最短时间):
在这里插入图片描述

时间复杂度:O(N^2)

猜你喜欢

转载自blog.csdn.net/qq_45678698/article/details/120275493