整数二分
//区间被划分为[l,mid] [mid+1,r]使用
//可查找target的最左位置
public int bSearch1(int[] nums, int l, int r) {
while (l < r) {
int mid = l + r >> 1;
if (check(mid)) r = mid;//check()判断mid是否满足
else l = mid + 1;
}
return l;
}
//区间被划分为[l,mid-1] [mid,r]使用
//可查找taget的最右位置
public int bSearch2(int[] nums, int l, int r) {
while (l < r) {
int mid = r + l + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
return l;
}
注意第二种情况mid=r+l+1>>1
浮点二分
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
double d=sc.nextDouble();
double l=-10000;
double r=10000;
while(r-l>Math.pow(10,-8)){
double mid=(r+l)/2;
if(mid*mid*mid>=d)r=mid;
else
l=mid;
}
System.out.println(String.format("%.6f", l));
}
}
浮点二分:
1.while(r-l>1e-8))答案要求精确6位小数,可设置终止条件为-8次方
2.浮点边界不需要+1.(l=mid,r=mid)
3.输出保留六位小数浮点数的格式
大整数加减乘除
//将BigInteger的十进制字符串表示形式转换为BigInteger。
BigInteger num=new BigInteger(String val)
使用
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
BigInteger a = sc.nextBigInteger();
BigInteger b = sc.nextBigInteger();
//减法
System.out.println(a.subtract(b));
//加法
System.out.println(a.add(b));
//除法
System.out.println(a.divide(b));
//乘法
System.out.println(a.multiply(b));
//取余
System.out.println(a.mod(b));
}
前缀与差分
双指针算法
双指针算法一般能将双循环遍历(O(N*N))优化为O(n)
需要找出双指针i,j的单调性联系,即可使用双指针
数组模拟栈和队列
单指针模拟栈
private static int p=0;
private static int[] stack=new int[100010];
public static void push(int val){
stack[++p]=val;
}
public static void pop(){
p--;
}
public static void empty(){
if(p==0)
System.out.println("YES");
else
System.out.println("NO");
}
public static int query(){
return stack[p];
}
双指针模拟队列
private static int[] queue=new int[100010];
private static int l=0,r=0;
public static void push(int val){
queue[r++]=val;
}
public static void pop(){
l++;
}
public static void empty(){
if(r-l==0)
System.out.println("YES");
else
System.out.println("NO");
}
public static void query(){
System.out.println(queue[l]);
}
单调栈
如果求右边第一个(大值/小值)倒序遍历,左边则正序遍历
import java.util.*;
class Solution {
public int[] dailyTemperatures(int[] T) {
int len=T.length;
int[] res=new int[len];
Stack<Integer> stack=new Stack<>();
for(int i=len-1;i>=0;i--){
while(!stack.isEmpty()&&T[stack.peek()]<=T[i]){
stack.pop();
}
res[i]=stack.isEmpty()?0:stack.peek()-i;
stack.push(i);
}
return res;
}
}
单调队列
滑动窗口
单调队列核心思想:删除冗余数据,保持队列单调性
使用双端队列Dque,可以从尾部删除数据
Deque<Integer> deque=new LinkedList<>();
for(int i=0;i<n;i++){
nums[i]=sc.nextInt();
//队列头部元素是否超出窗口范围
if(!deque.isEmpty()&&i-deque.peekFirst()>=k){
deque.pollFirst();
}
//将新元素与队列后端元素比较,大于num[i]的元素poll,保持队列单调性
while(!deque.isEmpty()&&nums[i]<nums[deque.peekLast()]){
deque.pollLast();
}
//将新元素加入队列
deque.offerLast(i);
//输出每个窗口的最小值
if(i>=k-1){
System.out.print(nums[deque.peekFirst()]+" ");
}
}
合并集合
import java.util.*;
public class Main{
static int n=100010;
//p[i]表示 i的父节点之一为p[i]
private static int[] p=new int[n];
//找到祖宗节点
//只有祖宗节点才有p[i]=i;
public static int find(int x){
while(x!=p[x]){
p[x]=p[p[x]];
x=p[x];
}
return x;
}
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int m=sc.nextInt();
//p[i]初始化,所有的p[i]=i,即初始所有节点的祖宗都是自己
for(int i=0;i<n;i++){
p[i]=i;
}
String opt;
int a,b;
for(int i=0;i<m;i++){
opt=sc.next();
a=sc.nextInt();
b=sc.nextInt();
if(opt.equals("M")){
p[find(a)]=find(b);
}else{
if(find(a)==find(b))
System.out.println("Yes");
else
System.out.println("No");
}
}
}
}
BFS求迷宫最短路径
DFS一般没有固定模板
BFS一般使用此模板
import java.util.*;
//存储路径
class Pair{
int x;
int y;
public Pair(int x,int y){
this.x=x;
this.y=y;
}
}
public class Main{
//地图
static int[][] arr=null;
//step[i][j]表示走到[i,j]一共走了多少步
static int[][] step=null;
//pairs[i][j]表示[i,j]是从pair走过来的
static Pair[][] pairs=null;
static int n;
static int m;
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
m=sc.nextInt();
arr=new int[n][m];
step=new int[n][m];
pairs=new Pair[n][m];
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
arr[i][j]=sc.nextInt();
}
}
System.out.println(bfs());
}
public static int bfs(){
Queue<Pair> queue=new LinkedList<>();
int[] dy = {0, 1, 0, -1}, dx = {-1, 0, 1, 0};
//将起始点放入队列
queue.offer(new Pair(0,0));
int x,y;
while(!queue.isEmpty()){
Pair pair=queue.poll();
for(int i=0;i<4;i++){
x=pair.x+dx[i];
y=pair.y+dy[i];
if(x>=0&&x<n&&y>=0&&y<m&&arr[x][y]==0&&step[x][y]==0){
step[x][y]=step[pair.x][pair.y]+1;
queue.offer(new Pair(x,y));
pairs[x][y]=pair;
}
}
}
//倒序打印最短路径
x=n-1;
y=m-1;
while(x!=0||y!=0){
System.out.println(x+" "+y);
Pair tmp=pairs[x][y];
x=tmp.x;
y=tmp.y;
}
return step[n-1][m-1];
}
}