poj3061尺取法/前缀和 二分(java)

简介: 今天遇到这题因为以前没见到过,当时就是想着应该有着一个很简单的方法可以过但是奈何就是没思路。后来看了别人思路写了下来。学习了尺取法

今天遇到这题因为以前没见到过,当时就是想着应该有着一个很简单的方法可以过但是奈何就是没思路。后来看了别人思路写了下来。学习了尺取法


题目介绍:



Description


A sequence of N positive integers (10 < N < 100 000), each of them less than or equal 10000, and a positive integer S (S < 100 000 000) are given. Write a program to find the minimal length of the subsequence of consecutive elements of the sequence, the sum of which is greater than or equal to S.


(给出N个正整数(10 <100 000)的序列,每个正整数小于或等于10000,并且给出正整数S(S <100 000 000)。编写程序以找到序列的连续元素的子序列的最小长度,其总和大于或等于S.)


Input


The first line is the number of test cases. For each test case the program has to read the numbers N and S, separated by an interval, from the first line. The numbers of the sequence are given in the second line of the test case, separated by intervals. The input will finish with the end of file.


(第一行是测试用例的数量。对于每个测试用例,程序必须从第一行读取数字N和S,以间隔分隔。序列的编号在测试用例的第二行中给出,以间隔分开。输入将以文件结尾结束。)


Output


For each the case the program has to print the result on separate line of the output file.if no answer, print 0.


Sample Input


2

10 15

5 1 3 5 10 7 4 9 2 8

5 11

1 2 3 4 5


Sample Output


2

3


思路的萌发:


最开始的傻D思路:暴力破解,从长度1开始暴力。o(n3)超时。

前缀和 二分:把前面的和用sum[]求出来。然后从第一项到最后一项一个个求,因为有sum[],所以每一个都用二分查找,然后剪枝考虑省去一些不必要的步骤。可以获得答案。

复杂度o(nlogn);


尺取法:这个方法非常巧妙,复杂度是o(n),他核心思想就是用一个段长当作可移动伸缩的尺子(左,右点向右移动)。求最短长就相当于 一个卷尺从头开始移动到各个点拉长,在这过程中。如果尺子长度大于需要的长,那么左面一直往前面移动,并且做相应记录,知道短了右侧需要继续加长。这种情况可以遍历所有满足的情况,复杂度非常低。


所有这题的尺取法就是 用一个sum从开始记录和,尺取法跑一圈


二分:


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.Scanner;
public class poj3601 {
/*
 * 二分法
 */
  public static void main(String[] args) throws IOException {
    // TODO 自动生成的方法存根
    StreamTokenizer in=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    PrintWriter out=new PrintWriter(new OutputStreamWriter(System.out));
    in.nextToken();int t=(int)in.nval;
    for(int i=0;i<t;i++)
    {
      in.nextToken();int a=(int)in.nval;
      in.nextToken();int b=(int)in.nval;
      int c[]=new int[a]; int len=Integer.MAX_VALUE;
      long sum[]=new long[a+1];//
      for(int j=0;j<a;j++)
      {
        in.nextToken();c[j]=(int)in.nval;
        sum[j+1]+=sum[j]+c[j];
      }   
      int left=0;int right=a;
      for(int j=0;j<a;j++)
      {
        int l=j;
        int r=(len==Integer.MAX_VALUE?a:(len+l>a?a:len+l));//右面长度存在不,不存在从a二分。如果存在加上这个点保证不能越界
        boolean jud=false;//用于终止循环
        while(true)
        {   
          if(sum[r]-sum[l]>=b)//如果大于目标进行二分
          {
            if(r-l<len) {len=r-l;}
              r=(l+r)/2;  
          }
          else//小于目标直接向右增加寻找目标,找到的第一个就是极限最短,在这区间不能越界,长度不能超多已经知道最短长度
          {
            for(;r<=a+1;r++)
            {             
              if(r>a) {jud=true;break;}
              if(r-l>=len) {jud=true;break;}
              if(sum[r]-sum[l]>=b) {len=r-l;break;}
            }         
          }
          if(jud) {break;}
        }
      }
      if(len!=Integer.MAX_VALUE) {out.println(len);}
      else out.println(0);
    }
    out.flush();
  }
}


尺取法:


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.Scanner;
public class poj3602尺取 {
/*
 * 尺取法
 */
  public static void main(String[] args) throws IOException {
    // TODO 自动生成的方法存根
    StreamTokenizer in=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    PrintWriter out=new PrintWriter(new OutputStreamWriter(System.out));
    in.nextToken();int t=(int)in.nval;
    for(int i=0;i<t;i++)
    {
      in.nextToken();int a=(int)in.nval;
      in.nextToken();int b=(int)in.nval;
      int c[]=new int[a]; int len=Integer.MAX_VALUE;
      long sum=0;
      for(int j=0;j<a;j++)
      {
        in.nextToken();c[j]=(int)in.nval;   
      }   
      sum=c[0];int l=0;int r=1;
      for(int j=1;j<a;j++)
      {
        sum+=c[j];
        while(sum>b)
        {
          if(len>j-l) {len=j-l;}
          if(len<=0) {break;}
          sum-=c[l++];
        }
      }
      if(len!=Integer.MAX_VALUE) {out.println(len+1);}
      else out.println(0);      
    }
    out.flush();
  }
}


目录
相关文章
【Java每日一题,前缀和】csp202203-2 出行计划
【Java每日一题,前缀和】csp202203-2 出行计划
|
机器学习/深度学习 Java
【Java每日一题,前缀和】天上的星星
【Java每日一题,前缀和】天上的星星
|
存储 机器人 Java
《备战蓝桥》之二分(Java)
二分的思想就是: 设定左右两个端点,给出判断条件,每次经过判断后都会减少一半数据,最后两个端点无限逼近,夹出符合判断条件的临界答案。
88 0
《备战蓝桥》之二分(Java)
详解 「二分滑动窗口」& 「双指针」,从 O(NlogN) 到 O(N) 的优化 | Java 刷题打卡
详解 「二分滑动窗口」& 「双指针」,从 O(NlogN) 到 O(N) 的优化 | Java 刷题打卡
|
人工智能 算法 Java
多解法综合题:「动态规划」&「前缀和 二分」&「双指针」| Java 刷题打卡
多解法综合题:「动态规划」&「前缀和 二分」&「双指针」| Java 刷题打卡
|
Java 索引 Python
啥是前缀和呀?图解前缀和(含模板)| Java 刷题打卡
啥是前缀和呀?图解前缀和(含模板)| Java 刷题打卡
下次如何在 30 秒内做出来?二维前缀和模板如何记忆 | Java 刷题打卡
下次如何在 30 秒内做出来?二维前缀和模板如何记忆 | Java 刷题打卡
|
存储 算法 Java
二维最长上升子序列:朴素 DP & 二分 DP(含证明)& 树状数组 DP | Java 刷题打卡
二维最长上升子序列:朴素 DP & 二分 DP(含证明)& 树状数组 DP | Java 刷题打卡
详解如何利用二分解决「搜索旋转排序数组」问题|Java 刷题打卡
详解如何利用二分解决「搜索旋转排序数组」问题|Java 刷题打卡
详解如何二分找分段有序数组的旋转点|Java 刷题打卡
详解如何二分找分段有序数组的旋转点|Java 刷题打卡