文章目录
导入
都是模板题,理解 + 背过就行
【快排】AcWing 785.快速排序
题目链接:acwing快速排序
题目
快排思路解释
第一步:确定分界点(假设值为x):arr[l],arr[r],arr[(l+r) /2],arr[随机下标]理论上都可以,但是注意边界处理。
⭐第二步:调整区间:所有<=x的在左半边,所有>=x的在右半边。
第三步:递归处理左右两端。
代码展示
输入比较大,比较多,java使用Bufferreader。
快排属于分治算法,分治算法都有三步:
1,分成子问题
2,递归处理子问题
3,子问题合并(快排这一步不需要操作,但归并排序的核心在这一步骤)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main{
static int N = 100010;
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(reader.readLine());
int arr[] = new int[N];
//Bufferreader输入是字符串数组,所以要把字符串再用Integer.parseInt()转化。
String strs[] = reader.readLine().split(" ");
for(int i = 0;i < n;i++){
arr[i] = Integer.parseInt(strs[i]);
}
quickSort(arr,0,n - 1);
for(int i = 0;i < n;i++){
System.out.print(arr[i] + " ");
}
}
public static void quickSort(int arr[],int l,int r){
if(l >= r) return;//递归终止条件
int mid = arr[(l + r) / 2];//随机一个数组里面的值
//1,分成子问题
int p1 = l-1;
int p2 = r+1;
while(p1 < p2){
do{p1++;} while(arr[p1] < mid);
do{p2--;} while(arr[p2] > mid);
if(p1 < p2){
int temp = arr[p1];
arr[p1] = arr[p2];
arr[p2] = temp;
}
}
//2,递归处理子问题
quickSort(arr,l,p2);
quickSort(arr,p2+1,r);
}
}
递归处理子问题解释为什么是终止到p2
递归处理子问题中: quickSort(arr,l,p2)-------------quickSort(arr,p2+1,r);
为什么不能用--------quickSort(arr,l,p1)-------------quickSort(arr,p1+1,r);
⭐误区:终止时,l和r不一定相等,可能r比l提前一位(例:3 5 4 1 2 2 4 5,第一次终止时,p1在下标为1,p2在下标为0位置)
⭐解释:a[i] 是一定大于等于 x 的,你把a[i]划到左边,可能使左边序列存在大于 x 的元素,并不能保证左边元素均小于等于 x。
【快排】AcWing 786. 第k个数
题目链接 AcWing 786. 第k个数
题目
代码展示
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int k = sc.nextInt();
int arr[] = new int[100010];
for(int i = 0;i < n;i++) arr[i] = sc.nextInt();
System.out.println(quickSort(arr,0,n - 1,k));
}
public static int quickSort(int arr[],int l,int r,int k){
if(l >= r) return arr[l];//因为是函数是返回int类型,所以要返回arr[l]或arr[r]
int mid = arr[(l + r) / 2];
int p1 = l - 1;
int p2 = r + 1;
while(p1 < p2){
do{p1++;}while(arr[p1] < mid);
do{p2--;}while(arr[p2] > mid);
if(p1 < p2){
int t = arr[p1];
arr[p1] = arr[p2];
arr[p2] = t;
}
}
//sl——左半部分长度
int sl = p2 - l + 1;
//判断k在左半部分还是右半部分,再递归
if(k <= sl){
return quickSort(arr,l,p2,k);
}
return quickSort(arr,p2 + 1,r,k - sl);
}
}
【归并】AcWing 787. 归并排序
题目链接:787. 归并排序
题目
代码思路
void merge_sort(int q[], int l, int r) {
递归的终止情况
if(l >= r) return;
第一步:分成子问题
int mid = l + r >> 1;
第二步:递归处理子问题
merge_sort(q, l, mid ), merge_sort(q, mid + 1, r);
第三步:合并子问题
int k = 0, i = l, j = mid + 1, tmp[r - l + 1];
while(i <= mid && j <= r)
if(q[i] <= q[j]) tmp[k++] = q[i++];
else tmp[k++] = q[j++];
while(i <= mid) tmp[k++] = q[i++];
while(j <= r) tmp[k++] = q[j++];
for(int i = 0;i < temp.length;i++) arr[l++] = temp[i];
代码展示
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main{
public static void main(String[] args) throws IOException{
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(reader.readLine());
String strs[] = reader.readLine().split(" ");
int arr[] = new int[100010];
for(int i = 0;i < n;i++){
arr[i] = Integer.parseInt(strs[i]);
}
mergeSort(arr,0,n - 1);
for(int i = 0;i < n;i++){
System.out.print(arr[i] + " ");
}
}
public static void mergeSort(int arr[],int l,int r){
if(l >= r) return;
int mid = (l + r) / 2;
mergeSort(arr,l,mid);
mergeSort(arr,mid + 1,r);
int p1 = l,p2 = mid + 1,k = 0;
int temp[] = new int [r - l + 1];
while(p1 <= mid && p2 <= r){
if(arr[p1] <= arr[p2]){
temp[k++] = arr[p1++];
}
else{
temp[k++] = arr[p2++];
}
}
while(p1 <= mid) temp[k++] = arr[p1++];
while(p2 <= r) temp[k++] = arr[p2++];
for(int i = 0;i < temp.length;i++){
arr[l++] = temp[i];
}
}
}
【二分】AcWing 789. 数的范围
题目链接:789. 数的范围
题目
关于代码
⭐记得二分的mid也是从中间分开,mid = l + (r - l) / 2
代码展示
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String nums[] = reader.readLine().split(" ");
int n = Integer.parseInt(nums[0]);
int q = Integer.parseInt(nums[1]);
String str[] = reader.readLine().split(" ");
int arr[] = new int[n];
for (int i = 0; i < n; i++) arr[i] = Integer.parseInt(str[i]);
while (q-- > 0) {
int x = Integer.parseInt(reader.readLine());
System.out.println(left(arr, x) + " " + right(arr, x));
}
}
public static int left(int arr[],int x){
int l = 0,r = arr.length - 1;
while(l <= r){
int mid = l + (r - l) / 2;
if(arr[mid] > x) r = mid - 1;
else if(arr[mid] < x) l= mid + 1;
else r = mid - 1;
}
if(l >= 0 && l < arr.length && arr[l] == x) return l;
return -1;
}
public static int right(int arr[],int x){
int l = 0,r = arr.length - 1;
while(l <= r){
int mid = l + (r - l) / 2;
if(arr[mid] > x) r = mid - 1;
else if(arr[mid] < x) l = mid + 1;
else l = mid + 1;
}
if(r >= 0 && r < arr.length && arr[r] == x) return r;
return -1;
}
}
【二分】AcWing 790. 数的三次方根
题目链接:AcWing 790. 数的三次方根
题目
代码展示
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
double x = sc.nextDouble();
double l = -10000,r = 10000;
//经验:精度比所求精度高 2位
while((r - l) > 1e-8){
double mid = (l + r) / 2;
if(mid * mid * mid >= x){
r = mid;
}
else l = mid;
}
//输出l和r都可以。因为r - l <= 1e-8,即r和l保留小数点后六位的话俩数字一样
System.out.printf("%.6f",l);
}
}
【前缀和】AcWing 795. 前缀和
题目链接:AcWing 795. 前缀和
题目
代码展示
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int k = sc.nextInt();
int a[] = new int[100010];
int s[] = new int[100010];
for(int i = 1;i <= n;i++){
a[i] = sc.nextInt();
s[i] = s[i - 1] + a[i];
}
while(k-->0){
int l = sc.nextInt();
int r = sc.nextInt();
System.out.println(s[r] - s[l - 1]);
}
}
}
【差分】AcWing 797. 差分
题目链接:AcWing 797. 差分
题目
代码展示
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int s[] = new int[100010];
int a[] = new int[100010];
for(int i = 1;i <= n;i++){
s[i] = sc.nextInt();
a[i] = s[i] - s[i - 1];
}
while(m-->0){
int l = sc.nextInt();
int r = sc.nextInt();
int c = sc.nextInt();
a[l] += c;
a[r + 1] -= c;
}
for(int i = 1;i <= n;i++){
s[i] = s[i - 1] + a[i];
System.out.print(s[i] + " ");
}
}
}
【双指针】AcWing 799. 最长连续不重复子序列
题目
代码展示
import java.util.Scanner;
import java.util.Map;
import java.util.HashMap;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int arr[] = new int[n + 10];
for(int i = 0;i < n;i++){
arr[i] = sc.nextInt();
}
int res = 1;//不重复长度
int i = 0;//慢指针
Map<Integer,Integer> map = new HashMap<>();//记录出现次数
for(int j = 0;j < n;j++){
map.put(arr[j],map.getOrDefault(arr[j],0) + 1);//记录出现次数
while(map.get(arr[j]) > 1){//次数 > 1,删除记忆
map.put(arr[i],map.get(arr[i]) - 1);
i++;
}
res = Math.max(res,j - i + 1);
}
System.out.println(res);
}
}
【双指针】AcWing 800. 数组元素的目标和
题目链接:AcWing 800. 数组元素的目标和
题目
代码展示
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int x = sc.nextInt();
int arr[] = new int[100010];
int brr[] = new int[100010];
for(int i = 0;i < n;i++){
arr[i] = sc.nextInt();
}
for(int i = 0;i < m;i++){
brr[i] = sc.nextInt();
}
int l = 0,r = m - 1;
while(l < n && r >= 0){
if(arr[l] + brr[r] > x){
r--;
}
else if(arr[l] + brr[r] < x){
l++;
}
else{
System.out.print(l + " " + r);
break;
}
}
}
}
【双指针】AcWing 2816. 判断子序列
题目链接:AcWing 2816.判断子序列
题目
代码展示
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int a[] = new int[100010];
int b[] = new int[100010];
for(int i = 0;i < n;i++) a[i] = sc.nextInt();
for(int i = 0;i < m;i++) b[i] = sc.nextInt();
int i = 0;
for(int j = 0;j < m;j++){
if(i < n && a[i] == b[j]) i++;
if(i == n) break;
}
if(i == n){
System.out.println("Yes");
}else{
System.out.println("No");
}
}
}
【位运算】AcWing 801. 二进制中1的个数
题目链接:AcWing 801.二进制中1的个数
题目
代码展示
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int arr[] = new int[n];
for(int i = 0;i < n;i++){
arr[i] = sc.nextInt();
}
for(int i = 0;i < n;i++){
int count = 0;
int x = arr[i];
//核心代码
while(x != 0){
x -= lowbit(x);
count++;
}
System.out.print(count+" ");
}
}
//得到x二进制表示中最右边的1所对应的数值
public static int lowbit(int x){
return x & (-x);
}
}
【区间合并】AcWing 803. 区间合并
题目链接:AcWing 803.区间合并
题目
代码展示
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
//用来放数组的集合list
ArrayList<int []> list = new ArrayList();
//把输入的区间都先放到集合里面
for(int i = 0;i < n;i++){
int a[] = new int[2];
a[0] = sc.nextInt();
a[1] = sc.nextInt();
list.add(a);
}
//对集合里面的数组,按照区间左端点进行排序
list.sort(new Comparator<int[]>(){
@Override
public int compare(int[] o1,int[] o2){
return o1[0] - o2[0];
}
});
//扫描整个区间,扫描过程中,把所有有交集的区间进行合并。
//具体做法:每次维护一个“当前区间”,扫描到第i个区间时候,判断与“当前区间”关系:
//情况1,第i个区间和“当前区间”有交集(含被包含情况),更新r(r = Math.max(r,a[1]));
//情况2,第i个区间和“当前区间”没有交集,k++就行,自动再是为第i个区间为“当前区间”
int k = 0;
int r = Integer.MIN_VALUE;
for(int a[] : list){
if(a[0] > r){
k++;
}
r = Math.max(r,a[1]);
}
System.out.println(k);
}
}