一、基础算法
1、快速排序
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class quickSort {
public static void main(String[] args) throws IOException {
BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(buf.readLine());
String []nums = buf.readLine().split(" ");
int []a = new int[n];
for (int i = 0; i < nums.length; i++) {
a[i] = Integer.valueOf(nums[i]);
}
quick_sort(a, 0, n - 1);
for (int i = 0; i < n; i++) {
System.out.print(a[i]+" ");
}
buf.close();
}
private static void quick_sort(int[]a, int l, int r){
if(l>=r){
return;
}
int x = a[l];
int i = l-1;
int j = r+1;
while(i<j){
do{
i++;
}while(a[i]<x);
do{
j--;
}while(a[j]>x);
if(i<j){
int t = a[i];
a[i] = a[j];
a[j] = t;
}
}
quick_sort(a , l , j);
quick_sort(a, j+1 , r);
}
}
2、归并排序
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class margeSort {
public static void main(String[] args) throws IOException {
BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(buf.readLine());
String[] a = buf.readLine().split(" ");
int q[] = new int[n];
for(int i = 0;i<n;i++){
q[i] = Integer.valueOf(a[i]);
}
marge_sort(q , 0 , n-1);
for (int i = 0; i < q.length; i++) {
System.out.println(q[i]);
}
}
public static void marge_sort(int []q ,int l ,int r){
if(l>=r){
return;
}
int mid = l+r>>1;
marge_sort(q , l , mid);
marge_sort(q , mid+1 , r);
int k = 0;
int i = l;
int j = mid+1;
int temp[] = new int[q.length];
while(i<=mid && j<=r){
if(q[i]>q[j]){
temp[k++] = q[j++];
}else{
temp[k++] = q[i++];
}
}
while(i<=mid){
temp[k++] = q[i++];
}
while(j<=r){
temp[k++] = q[j++];
}
for(int x = l,w = 0;x<=r;x++,w++){
q[x] = temp[w];
}
}
}
归并排序模板思路:首先进行递归,将所有的元素分成一小块一小块然后逐层进行归并,归并时设置一个临时数组用来存放比较后的数据,由于每次递归使用的元素都不一样,所以在归并时元素会被分成两组两组,不断向上进行比较,到最后一次归并只剩下两个有序数组,这是对这两个有序数组进行比较
1、设置返回语句
2、取到中间值
3、递归左边,递归右边
4、设置临时数组,临时数组指针,目标数组的两个指针
5、比较两个数组元素大小,然后将数组剩下的元素拼接到临时数组中
6、将临时数组的元素返回到数组中
y总笔记:
1、确定临界点:mid = l+r>>1;
2、递归左右两边
3、归并——合二为一
ACWing.788:逆序对的数量:
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int a[] = new int[n];
for(int i =0;i<n;i++){
a[i] = sc.nextInt();
}
long sum = marge_sort(a , 0 , n-1);
System.out.println(sum);
}
public static long marge_sort(int q[] ,int l ,int r){
if(l>=r){
return 0;
}
long res = 0L;
int mid = l+r>>1;
int temp[] = new int[r-l+1];
res += marge_sort(q , l , mid)+marge_sort(q , mid+1 , r);
int i = l;
int j = mid+1;
int k = 0;
while(i<=mid&&j<=r){
if(q[i]<=q[j]){
temp[k++] = q[i++];
}else {
temp[k++] = q[j++];
res += mid -i +1;
}
}
while(i<=mid){
temp[k++] = q[i++];
}
while(j<=r){
temp[k++] = q[j++];
}
for(i = l,j=0;i<=r; i++,j++){
q[i] = temp[j];
}
return res;
}
}
3、二分
先写check函数,判断l=mid还是r=mid,如果是l = mid,那么mid = l+r+1>>1,如果是r = mid,那么mid = l+r>>1。
二分思路:
先写出check函数,判断check函数true返回的结果是左边界等于mid,还是右边界等于mid。
如果左边界等于mid,则mid需要向上取整,即mid=l+r+1/2
如果右边界等于mid,则mid需要向下取整,即mid=l+r
模板1:
int mid = l + r + 1>>1;
if(check(mid)){
l = mid;
}else r = mid -1;
模板2:
int mid = l+r>>1;
if(check(mid)){
r = mid;
}else l = mid +1;
要点是判断mid开始的取值,如果判断结果取了l = mid ,则mid = l +r+1>>1
如果判断取了r = mid , 则mid = l+r>>1;
ACWing.789:
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int q = sc.nextInt();
int a[] = new int[n];
for(int i = 0;i<n;i++){
a[i] = sc.nextInt();
}
while(q-- != 0){
int s = sc.nextInt();
int l = 0;
int r = n-1;
while(l<r){
int mid = l+r>>1;
if(a[mid]>=s){
r = mid;
}else l = mid+1;
}
if(a[l]!=s){
System.out.println("-1 -1");
}else { System.out.print(l+" ");
l = 0;
r = n-1;
while(l<r){
int mid = l+r+1>>1;
if(a[mid]<=s){
l = mid;
}else r = mid-1;
}
System.out.println(l);
}
}
}
}
ACWing:T790
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 = 0;
double r = Math.abs(x)+1;
while(r - l>1e-8){
double mid = (l+r)/2;
if(mid*mid*mid>=Math.abs(x)){
r = mid;
}else l = mid;
}
if(x>=0){
System.out.printf("%.6f" , r);
}else{
System.out.print("-");
System.out.printf("%.6f" , r);
}
}
}
4、高精度加法
用代码体现运算过程
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
public class Main{
public static void main(String[] args) throws IOException {
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
String a = bf.readLine();
String b = bf.readLine();
List<Integer> list = add(a , b);
for(int i = list.size()-1;i>=0;i--){
System.out.print(list.get(i));
}
}
public static List<Integer> add(String a, String b){
int i = a.length()-1;
int j = b.length()-1;
List<Integer> res = new ArrayList<>();
int t = 0;
for(;i>=0||j>=0 ;i--,j--){
t+=(i>=0?a.charAt(i)-'0':0)+(j>=0?b.charAt(j)-'0':0);
res.add(t%10);
t = t/10;
}
if(t!=0)res.add(t);
return res;
}
}
4、高精度减法
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
public class GaoJingJian {
public static void main(String[] args) throws IOException {
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
String a = bf.readLine();
String b = bf.readLine();
ArrayList<Integer> aa = new ArrayList<>();
ArrayList<Integer> bb = new ArrayList<>();
for(int i = a.length()-1;i>=0;i--){
aa.add(a.charAt(i)-'0');
}
for(int i = b.length()-1;i>=0;i--){
bb.add(b.charAt(i)-'0');
}
if(check(a , b)){
List<Integer> cc = sub(aa , bb);
for(int i = cc.size()-1;i>=0;i--){
System.out.print(cc.get(i));
}
}else {
List<Integer> cc = sub(bb , aa);
System.out.print('-');
for(int i = cc.size()-1;i>=0;i--){
System.out.print(cc.get(i));
}
}
}
public static boolean check(String a , String b){
if(a.length()!=b.length()){
return a.length()>b.length();
}
for(int i = 0;i<a.length();i++){
if(a.charAt(i)!=b.charAt(i)){
return a.charAt(i)>b.charAt(i);
}
}
return true;
}
public static List<Integer> sub(ArrayList<Integer> a , ArrayList<Integer> b){
List<Integer> list = new ArrayList<>();
for(int i = 0 , t = 0;i<a.size();i++){
t = a.get(i) - t;
if(i<b.size()) t = t - b.get(i);
list.add((t+10)%10);
if(t<0) t = 1;else t = 0;
}
int i = list.size()-1;
while(i>0){
if(list.get(i)==0){
i--;
}else break;
}
return list.subList(0 , i+1);
}
}
高精度减法思路:首先判断两个数大小,通过判断结果决定是否输出负号
然后利用一个变量t表示向前借位,(t+10)%10,如果t为整数,那么该数不变,最后将该数赋值为0,如果t为负数,那么该数成功向前一位借位,最后将该数赋值为1。
最后去除前导零。
5、高精度乘法
import java.io.*;
import java.util.*;
public class Main{
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String a = br.readLine();
int bb = Integer.valueOf(br.readLine());
ArrayList<Integer> aa = new ArrayList<Integer>();
for (int i = a.length() - 1; i >= 0; i--){
aa.add(a.charAt(i) - '0');
}
ArrayList<Integer> c = add2(aa,bb);
boolean t = true;
for(int k = c.size() - 1; k >= 0 ; k--){
if(c.get(k) == 0 && t && k >= 1) continue;
System.out.print(c.get(k));
t = false;
}
}
public static ArrayList<Integer> add2(ArrayList<Integer> aa, int bb){
ArrayList<Integer> c = new ArrayList<Integer>();
int t = 0;
for(int i = 0; i < aa.size(); i++){
t += aa.get(i) * bb;
c.add((t % 10));
t /= 10;
}
if (t > 0) c.add(t);
int i = 0;
return c;
}
}
评价:不如BigInteger
6、前缀和
前缀和总结:
思路:s[r]-s[l-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 m = sc.nextInt();
int a[] = new int[n+1];
int s[] = new int[n+1];
for(int i = 1;i<=n;i++){
a[i] = sc.nextInt();
}
for(int i = 1;i<=n;i++){
s[i] = a[i] + s[i-1];
}
while(m-->0){
int l = sc.nextInt();
int r = sc.nextInt();
System.out.println(s[r] - s[l-1]);
}
}
}
s[i , j] - s[i-1 , j] - s[i , j-1] + s[i-1 , j-1]:
7、差分
差分最重要的就是,可以在差分数组中,批量的对原数组进行操作。
T797:
import java.util.*;
public class Main{
static int N = 100010;
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int []arr = new int[N];
int []b = new int[N];
for(int i = 1;i<=n;i++){
arr[i] = sc.nextInt();
}
for(int i = 1;i<=n;i++){
insert(b , i , i , arr[i]);
}
for(int j = 0;j<m;j++){
int l = sc.nextInt();
int r = sc.nextInt();
int c = sc.nextInt();
insert(b , l , r , c);
}
for(int i = 1;i<=n;i++){
b[i] = b[i] + b[i-1];
System.out.print(b[i]+" ");
}
}
public static void insert(int b[] , int l , int r , int c){
b[l] = b[l]+c;
b[r+1] = b[r+1]-c;
}
}
T798:差分矩阵
import java.util.*;
public class Main{
static int N = 1010;
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int q = sc.nextInt();
int a[][] = new int[N][N];
int b[][] = new int[N][N];
for(int i = 1;i<=n;i++){
for(int j = 1;j<=m;j++){
a[i][j] = sc.nextInt();
}
}
// 初始化差分b数组
for(int i = 1;i<=n;i++){
for(int j = 1;j<=m;j++){
insert(b , i , j , i , j ,a[i][j]);
}
}
while(q--!=0){
int x1 = sc.nextInt();
int y1 = sc.nextInt();
int x2 = sc.nextInt();
int y2 = sc.nextInt();
int c = sc.nextInt();
insert(b , x1 , y1 , x2 , y2 , c);
}
for(int i = 1;i<=n;i++){
for(int j = 1;j<=m;j++){
a[i][j] = b[i][j] - a[i-1][j-1] + a[i][j-1] + a[i-1][j];
System.out.print(a[i][j]+" ");
}
System.out.println();
}
}
public static void insert(int b[][] , int x1 , int y1 , int x2 , int y2 , int c){
b[x1][y1] += c;
b[x2+1][y2+1] += c;
b[x2+1][y1] -= c;
b[x1][y2+1] -= c;
}
}
8、双指针
模板:
for(int i = 0 , j = 0;i<n;i++){
while(j<i&&check(j))j++;
//具体题的逻辑
}
T799:
import java.util.*;
public class Main{
static int N = 100010;
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] a = new int[N];
int[] s = new int[N];
for(int i = 0;i<n;i++){
a[i] = sc.nextInt();
}
int j = 0;
int res = 0;//结果
//for内部:
//每次i往前走一个,判断该数是否重复,如果不重复,i继续往前走
//如果重复,j往前走,同时将已经放入判重数组的元素踢掉,直到走到重复元素为止
//此时j<i,因为j走到的是与i为下标的相等的元素上
for(int i = 0;i<n;i++){
s[a[i]] ++ ;
while(s[a[i]]>1){
s[a[j]]--;
j ++;
}
res = Math.max(res , i - j +1);
}
System.out.println(res);
}
}
9、位运算
常见的位运算操作:
n的二进制表示中第k位是几
求n的第k位数字:n>>k&1
返回n的最后一位1:lowbit(n) = n& -n
lowbit(x):返回最后一位1
10、离散化
1、数组中可能有重复元素(去重)
2、需要快速的映射,如何算出a[i]离散化后的值(二分)
//储存所有离散化的值
//排序所有值
//去重
import java.util.*;
public class Main{
static int N = 300010;
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();//存n次操作
int m = sc.nextInt();//存m次询问
int[] a = new int[N];
int[] s = new int[N];
List<Integer> list = new ArrayList<>();//存数轴
List<Paris> add = new ArrayList<>();//存n次操作
List<Paris> query = new ArrayList<>();//存m次询问
for(int i = 0;i<n;i++){
int first = sc.nextInt();
int second = sc.nextInt();
add.add(new Paris(first , second));
list.add(first);
}
for(int i = 0;i<m;i++){
int first = sc.nextInt();
int second = sc.nextInt();
query.add(new Paris(first , second));
list.add(first);
list.add(second);
}
Collections.sort(list);
int un = unic(list);
list = list.subList(0 , un);
for(Paris item : add){
int x = find(item.first , list);
a[x] += item.second;
}
for(int i = 1;i<=list.size();i++) s[i] = s[i-1]+a[i];
for(Paris item : query){
int l = find(item.first , list);
int r = find(item.second , list);
System.out.println(s[r] - s[l-1]);
}
}
static int find(int x, List<Integer> list){
int l = 0;
int r = list.size()-1;
while(l<r){
int mid = l+r>>1;
if(list.get(mid)>=x){
r = mid;
}else l = mid + 1;
}
return l+1;
}//二分查询,前缀和是以1开始,所以结尾要加1
static int unic(List<Integer> list){
int j = 0;
for(int i = 0;i<list.size();i++){
if(i == 0||list.get(i)!=list.get(i-1)){
list.set( j , list.get(i));
j++;
}
}
return j;
}//去重操作
}
class Paris{
int first;
int second;
public Paris(int first , int second){
this.first = first;
this.second = second;
}
}
思路:
使用一个容器来储存所有的值,使用一个集合作为映射集合(下标对应数组下标,集合内对应元素),使用一个数组作为被操作数组。
11、区间合并
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
List<int[]> list = new ArrayList<>();
List<int[]> res = new ArrayList<>();
for(int i = 0;i<n;i++){
int first = sc.nextInt();
int second = sc.nextInt();
list.add(new int[]{first , second});
}
list.sort(new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[0] - o2[0];
}
});
int st = Integer.MIN_VALUE;
int ed = Integer.MIN_VALUE;
for(int[] a : list){
if(a[0]>ed){
if(st !=Integer.MIN_VALUE){
res.add(new int[]{st , ed});
}
st = a[0];
ed = a[1];
}else{
ed = Math.max(ed , a[1]);
}
}
if (st != Integer.MIN_VALUE){
res.add(new int[]{st , ed});
}
System.out.println(res.size());
}
}