• 51nod 1272 最大距离


    题目网站:http://class.51nod.com/Challenge/Problem.html#problemId=1272

    一、题目描述

    给出一个长度为N的整数数组A,对于每一个数组元素,如果他后面存在大于等于该元素的数,则这两个数可以组成一对。
    每个元素和自己也可以组成一对。例如:{5, 3, 6, 3, 4, 2},可以组成11对,如下(数字为下标):
    (0,0), (0, 2), (1, 1), (1, 2), (1, 3), (1, 4), (2, 2), (3, 3), (3, 4), (4, 4), (5, 5)。其中(1, 4)是距离最大的一对,距离为3。

    输入描述

    第1行:1个数N,表示数组的长度(2 <= N <= 50000)。
    第2 - N + 1行:每行1个数,对应数组元素Ai(1 <= Ai <= 10^9)。

    输出描述

    输出最大距离。

    样例输入

    6
    5
    3
    6
    3
    4
    2

    样例输出

    3

    二、解题思路

    这道题发明了一个方法(也可以用单调栈 / 单调队列来做),我自己起了个名字叫做 “ 前缀赛梯法 ” 。很好玩吧,但是是个有意义的名字
    这个方法也不能叫做方法吧,但可以称之为技巧。
     
    能作为这两个数中的前一个数要满足的要求:前面没有小于他的
    (我们把能满足这个要求的所有数字都存到A数组里)
     
    能作为这两个数中的后一个数要满足的要求:后面没有大于他的
    (我们把能满足这个要求的所有数字都存到B数组里)
     
    相信大家读题的时候也已经发现了,我们要找的是他后面所有比这个数大于或等于的数。
    我们不能比较附近挨着的两个,我们得把所有的都比较一遍,我给大家建议的方法就是:
     
    一边输入也可以一边找出A数组中存什么数字好,输入完了后我们可以从N-1 —> 0 在来一次循环找出B数组里的数
     
    至于怎么找呢?
     
    我们可以记录下A数组里上一个数的下标,把 a[这个数] 和现在这个数进行比较,如果现在这个数小于上次存的那个数
    A数组里多存一个i(我往A数组里存的都是下标),上次那个数的下标变成这次的下标。
     
    A数组存数字的方法:
    for(int i = 0;i < n;i++){
            cin >> a[i];
            if(prenum == 0 || a[i] < a[A[prenum-1]]){
                A[prenum++] = i;
            }
        }

    1、一边输入一边存

    2、prenum里面记录的是(上一次存进A数组里那个数的,在A数组里的)下标。

       如果一开始还没存数进去 或者 已经存了的那个数,却发现这次的也符合题目的要求

    3、如果符合上面叙述的情况,把下标(i)存进A里面,A[prenum++] = i 

     
    B数组同理。
    B数组存数字的方法:
    for(int i = n-1;i >= 0;i--){
        if(postnum == 0 || a[i] > a[B[postnum -1]]){
            B[postnum++] = i;
        }
    }

    1、从n-1开始循环。因为这次我们要从后往前找符合这个条件的:后面没有大于他的

      (我是从0开始输入的,如果你从1开始的话最好把prenum和postnum都赋值为1,这样你往A数组和B数组里存数的时候就是从下标为1开始存了)

     2、prenum里面记录的是(上一次存进B数组里那个数的,在B数组里的)下标。

       如果一开始还没存数进去 或者 已经存了的那个数,却发现这次的也符合题目的要求

     3、如果符合上面叙述的情况,把下标(i)存进B里面, B[postnum++] = i

    这时候,A数组里肯定是降序的,B数组肯定也是降序的。大家自己思考一下这点。
     
    现在开始讲输出
     
    输出照常来说我们都要把A数组里的数和B数组里的数一一进行对比才能肯定哪个就是答案
    可是这里我们用了一个小技巧:
    假设A数组里有3个数,B数组里有3个数,正常情况来说需要判断9次,实际上这个代码可能只需要判断5次就出结果了。
    而且正常情况还会TLE(超出时间限制)
     
    那么我们这个不同寻常的技巧是什么?
    注意:A数组里肯定是降序的,B数组肯定也是降序的
     
    if(A数组里的数是小于B数组里的数的){
           ans和这次的答案取一个最大值
      A数组再往前一个数
    }else{
      //A数组里的数比B数组里的数大
      B数组的数要往前一个数,看看前面的数可不可以,因为前面的数大一点
    }
     
    在我的代码中我为了输出定义了两个数
    1、pre_idx 的意思是现在A数组查到哪个数了,如果待会的答案是可以的,使A数组往前一个数就相当于pre_idx-1
    2、post_idx 的意思是现在B数组查到哪个数了,如果待会的答案不可以,使B数组往后一个数就相当于post_idx-1
    long long pre_idx = 0, post_idx = postnum -1;
    for(;pre_idx < prenum && post_idx >= 0;){
        if(a[A[pre_idx]] <= a[B[post_idx]]){
            ans = max(B[post_idx] - A[pre_idx], ans);
            --post_idx;
        }else{
            ++pre_idx;
        }
    }

     输出的话我也自己起了个名字:AB判断法

    是不是很生动:)

    判断AB两个数组哪个下标会变

    三、代码描述 

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    long long n, a[50010], A[50010], B[50010];
    long long cnt_a=1, cnt_b=1, ans, prenum, postnum;
    
    int main(){
        cin >> n;
        for(int i = 0;i < n;i++){
            cin >> a[i];
            if(prenum == 0 || a[i] < a[A[prenum-1]]){
                A[prenum++] = i;
            }
        }
        for(int i = n-1;i >= 0;i--){
            if(postnum == 0 || a[i] > a[B[postnum -1]]){
                B[postnum++] = i;
            }
        }
        long long pre_idx = 0, post_idx = postnum -1;
        for(;pre_idx < prenum && post_idx >= 0;){
            if(a[A[pre_idx]] <= a[B[post_idx]]){
                ans = max(B[post_idx] - A[pre_idx], ans);
                --post_idx;
            }else{
                ++pre_idx;
            }
        }
        cout << ans << endl;
        return 0;
    }
  • 相关阅读:
    [Leetcode Week3]Evaluate Division
    [Leetcode Week3]Course Schedule
    [Leetcode Week3]Clone Graph
    [Leetcode Week2]Sort List
    [Leetcode Week2]Sort Colors
    [Leetcode Week2]Merge Intervals
    [Leetcode Week1]Longest Substring Without Repeating Characters
    哈夫曼树的数组实现
    cocos2d-x3.16 default模式项目 Android Studio C++文件编译失败问题
    html display和visibility在资源加载上的区别
  • 原文地址:https://www.cnblogs.com/elisa02/p/13263452.html
Copyright © 2020-2023  润新知