B1040 有几个PAT 与 A1101 Quick Sort

活用递推 — 《算法笔记》

在这里插入图片描述

  • 就是找个方法分别对某个位置的左右两边进行处理,最后得到该位置的值
  • 对左右两边的处理最好是可以使用递推做到的

1040 有几个PAT

1040 有几个PAT
字符串 APPAPT 中包含了两个单词 PAT,其中第一个 PAT 是第 2 位§,第 4 位(A),第 6 位(T);第二个 PAT 是第 3 位§,第 4 位(A),第 6 位(T)。

现给定字符串,问一共可以形成多少个 PAT?

输入格式:
输入只有一行,包含一个字符串,长度不超过10^​5​​ ,只包含 P、A、T 三种字母。

输出格式:
在一行中输出给定字符串中包含多少个 PAT。由于结果可能比较大,只输出对 1000000007 取余数的结果。

输入样例:
APPAPT

输出样例:
2

思路

在这里插入图片描述

  • 在从前往后扫描过程中,计算每个位置前面P的数量并使用数组保存
    即:此时体现了递推的思想:该位置前面P的数量,与上一个位置前面P的数量 和 该位置是不是P有关系
  • 再从后往前扫描:计算每个位置后T的数量,原理与上述相同
  • 这个时候对于每个位置都知道了该位置前面P的数量与位置后T的数量了
#include"stdio.h"
#include"string.h"

// 找PAT的个数 
int main(){
    
    
	const int MAXN = 100010;  // 最大位数 
	const int MOD = 1000000007;
	char str[MAXN];
	int leftNUMP[MAXN] = {
    
    0};
	int rightNUMT = 0;
	int ans = 0;  // 保存结果
	char c;
	int n = 0;
	while(~scanf("%c",&c))
    {
    
    
        if(c=='\n')
            break;
        str[n++]=c;
    }
    str[n] = '\0';
    
	int len = strlen(str);
	// 从左往右,找每一位以及之前 P的个数 
	for(int i=0; i<len; i++){
    
    
		if (i != 0){
    
    
			if (str[i] == 'P'){
    
    
				leftNUMP[i] = leftNUMP[i-1] + 1;
			}
			else{
    
    
				leftNUMP[i] = leftNUMP[i-1];
			} 
		}
		else{
    
    
			if (str[i] == 'P'){
    
    
				leftNUMP[i]++;
			}
			else{
    
    
				leftNUMP[i] = 0;
			}
		}
	}
	// 从右往左,找每一位以及之后的T的个数, 且如果是A,则需要计算结果并将其放入到ans中
	for(int i=len-1; i>=0; i--){
    
    
		if (str[i] == 'T'){
    
    
			rightNUMT++;
		}
		else if (str[i] == 'A'){
    
    
			ans = (ans + leftNUMP[i] * rightNUMT) % MOD;  // A所在位置前面的P的个数 乘以 所在位置后的T的个数 
		}
	} 
	printf("%d", ans); 
}

1101 Quick Sort

Quick Sort
There is a classical process named partition in the famous quick sort algorithm. In this process we typically choose one element as the pivot. Then the elements less than the pivot are moved to its left and those larger than the pivot to its right. Given N distinct positive integers after a run of partition, could you tell how many elements could be the selected pivot for this partition?

For example, given N = 5 and the numbers 1, 3, 2, 4, and 5. We have:

1 could be the pivot since there is no element to its left and all the elements to its right are larger than it;
3 must not be the pivot since although all the elements to its left are smaller, the number 2 to its right is less than it as well;
2 must not be the pivot since although all the elements to its right are larger, the number 3 to its left is larger than it as well;
and for the similar reason, 4 and 5 could also be the pivot.
Hence in total there are 3 pivot candidates.

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N (<= 105). Then the next line contains N distinct positive integers no larger than 109. The numbers in a line are separated by spaces.

Output Specification:

For each test case, output in the first line the number of pivot candidates. Then in the next line print these candidates in increasing order. There must be exactly 1 space between two adjacent numbers, and no extra space at the end of each line.

Sample Input:
5
1 3 2 4 5

Sample Output:
3
1 4 5

题目大意:
快速排序中,我们通常采用某种方法取一个元素作为主元,通过交换,把比主元小的元素放到它的左边,比主元大的元素放到它的右边。 给定划分后的N个互不相同的正整数的排列,请问有多少个元素可能是划分前选取的主元?例如给定N = 5, 排列是1、3、2、4、5。则:
1的左边没有元素,右边的元素都比它大,所以它可能是主元;
尽管3的左边元素都比它小,但是它右边的2它小,所以它不能是主元;
尽管2的右边元素都比它大,但其左边的3比它大,所以它不能是主元;
类似原因,4和5都可能是主元。
因此,有3个元素可能是主元。
给N个数,第一行输出可能是主元的个数,第二行输出这些元素

思路

与上一题一样:

  • 找该位置前面最大的元素a,找该位置后面最小的元素b,该位置元素需要大于a,小于b
#include"stdio.h"
#include"string.h"

// 找PAT的个数 
int main(){
    
    
	const int MAXN = 100010;  // 最大位数 
	const int MOD = 1000000007;
	char str[MAXN];
	int leftNUMP[MAXN] = {
    
    0};
	int rightNUMT = 0;
	int ans = 0;  // 保存结果
	char c;
	int n = 0;
	while(~scanf("%c",&c))
    {
    
    
        if(c=='\n')
            break;
        str[n++]=c;
    }
    str[n] = '\0';
    
	int len = strlen(str);
	// 从左往右,找每一位以及之前 P的个数 
	for(int i=0; i<len; i++){
    
    
		if (i != 0){
    
    
			if (str[i] == 'P'){
    
    
				leftNUMP[i] = leftNUMP[i-1] + 1;
			}
			else{
    
    
				leftNUMP[i] = leftNUMP[i-1];
			} 
		}
		else{
    
    
			if (str[i] == 'P'){
    
    
				leftNUMP[i]++;
			}
			else{
    
    
				leftNUMP[i] = 0;
			}
		}
	}
	// 从右往左,找每一位以及之后的T的个数, 且如果是A,则需要计算结果并将其放入到ans中
	for(int i=len-1; i>=0; i--){
    
    
		if (str[i] == 'T'){
    
    
			rightNUMT++;
		}
		else if (str[i] == 'A'){
    
    
			ans = (ans + leftNUMP[i] * rightNUMT) % MOD;  // A所在位置前面的P的个数 乘以 所在位置后的T的个数 
		}
	} 
	printf("%d", ans); 
}

另一种思路

其实可以这样想:前面的数大,比后面的数小,说明该位置就是排序后该值的正确位置

  • 进行排序,看看哪个位置上的值没有变化,那他可能是主元(因为可能前面有比他大或者后面比他小的数 — 对3而言:14325)
  • 再对该值进行判断:比较该值前面有没有比他大的数(只需要判断这个条件就好了,因为他的位置与排序后位置相同,而前面有比他大的,后面一定有比它小的,)

来自柳神的代码:

#include <iostream>
#include <algorithm>
#include <vector>
int v[100000];
using namespace std;
int main() {
    
    
    int n, max = 0, cnt = 0;
    scanf("%d", &n);
    vector<int> a(n), b(n);
    for (int i = 0; i < n; i++) {
    
    
        scanf("%d", &a[i]);
        b[i] = a[i];
    }
    sort(a.begin(), a.end());
    for (int i = 0; i < n; i++) {
    
    
        if(a[i] == b[i] && b[i] > max)
            v[cnt++] = b[i];
        if (b[i] > max)
            max = b[i];
    }
    printf("%d\n", cnt);
    for(int i = 0; i < cnt; i++) {
    
    
        if (i != 0) printf(" ");
        printf("%d", v[i]);
    }
    printf("\n");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43779658/article/details/114855449
今日推荐