尺取法

尺取法又叫双指针(two pointers)是竞赛中常用的优化基技巧,用来解决区间问题,操作简单。如果是单调区间也常用二分法

需要操作两个变量,可以用两个下标(指针)i,j 扫描区间。有二重循环,复杂度为O(n2)

for(int i=0;i<n;i++)
    for(int j=n-1;j>=0;j--)
        {
        }    

实际上尺取法就是把二重循环变为一个循环,在这个循环中同时处理i,j,时间复杂都也从O(n2)变为O(n)

int i=0;
int j=n-1;
while(i<j)
{
    .....i++;
    .....j--;

}
//用for实现
for(int i=0;j=n-1;i<j;i--;j++)
{
}

在扫描方式中有两种扫描方式

(1)反向扫描:i和j反向相同,i从头到尾,j从尾到头。在中将相会。

(2)同向扫描。又称快慢指针。都是从头到尾,速度不同。

反向扫描经典例题:

输入n个整数放在a[]中,找出其中两个数,他们之和等于整数m所有整数都是int类型

输入样例

9

21 4 5 6 13 65 32 9 23

28

输出

5 23

 import java.sql.Array;
 //import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Scanner;
 public class Main{
     public static void main(String[]args)
     {
         Scanner input=new Scanner(System.in);
         int n= input.nextInt();

int []ant=new int[n]; for(int i=0;i< ant.length;i++) { ant[i]= input.nextInt(); } int m= input.nextInt(); Arrays.sort(ant); int i=0;int j=n-1; while(i<j) { int sum=ant[i]+ant[j]; if(sum>m) { j--; } else if (sum<m) { i++; } else { System.out.println(ant[i]+" "+ant[j]); i++; } } } }

2 判断回文串

给定一个字符判定它是否是回文串

输入第一行输入一个整数n表示,表示测试实例个数。后面输入n个字符串

是回文输出yes,不是输出no

常规做法:

 import java.util.ArrayList;
 import java.util.Scanner;
 public class Main{
     public static void main(String[]args)
    {
         ArrayList<String> list=new ArrayList<>();
         Scanner input=new Scanner(System.in);
         int n= input.nextInt();
         while(n-->0)
         {
             String p= input.next();
             if(check(p))
             {
                 list.add("yes");
            }
             else{
                 list.add("no");
             }
         }
         for(int i=0;i< list.size();i++)
         {
             System.out.println(list.get(i));
         }
     }
     public static boolean check(String m)
     {
         StringBuilder st=new StringBuilder(m);
         st.reverse();
         int count=0;
         for(int i=0;i< st.length();i++)
         {
             if(st.charAt(i)!=m.charAt(i))
            {
                 return false;
             }
             else{
                 count++;
             }
         }
         if(count==m.length())
         {
             return true;
         }
         else{
             return false;
         }
     }
 }

 用尺取法判断回文串,采用双指针的算法

import java.util.ArrayList;
import java.util.Scanner;
public class Main
{
    public static void main(String[]args)
    {
        Scanner input=new Scanner(System.in);
        ArrayList<String> list=new ArrayList<>();
        int n= input.nextInt();
        while(n-->0)
        {
            boolean key=true;
            String s= input.next();
            int i=0;
            int j=s.length()-1;
            while(i<j)
            {
                if(s.charAt(i)!=s.charAt(j))
                {
                    key=false;
                   break;
                }
                i++;
                j--;
            }
            if(key)
            {
                list.add("YES");
            }
            else{
                list.add("NO");
            }
        }
        for(int i=0;i< list.size();i++)
        {
            System.out.println(list.get(i));
        }
    }
}

 

 寻找区间和,给定一个数组,在数组中找到一个区间,使得这个区间和等于S 输出起点和终点的位置

package Main6;

import java.util.Scanner;
public class Main{
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        int[] ant = new int[n];
        for (int i = 0; i < n; i++) {
            ant[i] = input.nextInt();
        }
        int s = input.nextInt();
        int i = 0;
        int j = 0;
        int sum = ant[0];
        while (j < n) {
            if (sum >= s){
                if(sum==s) System.out.println(i+" "+j);
                sum-=ant[i];
                i++;
                if(i>j&&i<ant.length) {sum=ant[i];j++;}
            }
            if(sum<s) {j++; if(j<ant.length)sum+=ant[j];}
        }
    }
}

 

 

 

 找相同数对,给定一串数,以及一个数字C要求计算A-B=C的数对的个数

import java.util.Arrays;
import java.util.Scanner;
public class Main{
    public static void main(String[]args)
    {
        Scanner input=new Scanner(System.in);
        int n= input.nextInt();
        int c= input.nextInt();
        int []ant=new int[n+1];
        for(int i=1;i<=n;i++)
        {
            ant[i]= input.nextInt();
        }
        Arrays.sort(ant);
        long ans=0;
        for(int i=1,j=1,k=1;i<=n;i++)
        {
            while(j<=n&&ant[j]-ant[i]<c)
            {
                j++;
            }
            while(k<=n&&ant[k]-ant[i]<=c)
            {
                k++;
            }
            if(k-1>=1&&j<=n&&i<=n&&ant[j]-ant[i]==c&&ant[k-1]-ant[i]==c)
            {
                ans+=k-j;
            }
        }
        System.out.println(ans);
    }
}

 用尺取法进行数组去重复

import java.util.Arrays;

public class ArrayDeduplication {

    public static int[] removeDuplicates(int[] nums) {
        // 首先,判断数组是否为空或长度为0,如果是,则返回原数组
        if (nums == null || nums.length == 0) {
            return nums;
        }

        // 数组长度为1时也无需去重,直接返回原数组
        if (nums.length == 1) {
            return nums;
        }

        // 初始化双指针
        int left = 0; // 左指针用于记录不重复元素的位置
        int right = 1; // 右指针用于遍历数组

        // 开始尺取法去重
        while (right < nums.length) {
            // 如果当前右指针指向的元素与左指针指向的元素不相等
            // 则说明找到一个新的不重复元素
            if (nums[right] != nums[left]) {
                // 将不重复元素放到左指针的下一个位置
                nums[++left] = nums[right];
            }
            // 右指针继续向右移动
            right++;
        }

        // 返回去重后的数组,长度为left+1
        return Arrays.copyOf(nums, left + 1);
    }

    public static void main(String[] args) {
        int[] nums = {1, 1, 2, 2, 3, 4, 4, 5, 6, 6};
        int[] result = removeDuplicates(nums);

        System.out.println("去重后的数组为:");
        for (int num : result) {
            System.out.print(num + " ");
        }
    }
}

 

posted @ 2023-05-11 23:08  LILi2209  阅读(263)  评论(0)    收藏  举报