文章目录
- [1. 空调遥控](#1. 空调遥控)
- [2. kotori和气球](#2. kotori和气球)
- [3. 走迷宫](#3. 走迷宫)
- [4. 主持人调度II](#4. 主持人调度II)
- [5. 体操队形](#5. 体操队形)
- [6. 二叉树的最大路径和](#6. 二叉树的最大路径和)
- [7. 排序子序列](#7. 排序子序列)
- [8. 消减整数](#8. 消减整数)
1. 空调遥控
题目描述

解题思路
解法一:滑动窗口
时间复杂度:O(n * lonn) + O(n)
把数组排序,维护一个窗口,保证max-min<=2p,统计窗口长度,返回最大值
解法二:二分查找
时间复杂度:O(n * lonn ) + O(n * lonn )
把数组排序,枚举每一个温度,通过二分查找,分别找到arr[i]-p,arr[i]+p对应的下标,计算这个区间内人数总和,返回最大值即可
代码实现
java
import java.util.*;
import java.io.*;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
static Read in = new Read();
static PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
public static void main(String[] args) throws IOException{
int n = in.nextInt();
int p = in.nextInt();
long[] arr = new long[n];
for(int i= 0;i<n;i++)
arr[i] = in.nextLong();
Arrays.sort(arr);
int left = 0;
int right = 0;
int ret = 0;
while(right<n){
while(left<=right && (arr[right]-arr[left])>2*p)
left++;
ret = Math.max(right-left+1,ret);
right++;
}
System.out.println(ret);
out.close();
}
}
class Read{
StringTokenizer st = new StringTokenizer("");
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
String next() throws IOException{
while(!st.hasMoreTokens()){
st = new StringTokenizer(bf.readLine());
}
return st.nextToken();
}
int nextInt() throws IOException{
return Integer.parseInt(next());
}
long nextLong() throws IOException{
return Long.parseLong(next());
}
}
2. kotori和气球
题目描述

解题思路
排列组合
第一个位置n种选择,其余位置n-1种选择
代码实现
java
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
int ans = n;
for(int i = 1;i<m;i++){
ans=ans*(n-1)%109;
}
System.out.println(ans);
}
}
3. 走迷宫
题目描述

解题思路
最短路径 --》 BFS
注意: 下标从1开始,字符串要先前置一个" " 再填写到grid中
代码实现
java
import java.util.*;
import java.io.*;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
static Read in = new Read();
public static void main(String[] args) throws IOException {
int n = in.nextInt();
int m = in.nextInt();
int xs = in.nextInt();
int ys = in.nextInt();
int xt = in.nextInt();
int yt = in.nextInt();
int[] dx = {0, 0, 1, -1};
int[] dy = {1, -1, 0, 0};
if (xs == xt && ys == yt) {
System.out.println(0);
return;
}
boolean[][] check = new boolean[n + 1][m + 1];
char[][] grid = new char[n + 1][m + 1];
for (int i = 1; i <= n; i++) {
String str = in.next();
str = " "+str;
grid[i] = str.toCharArray();
}
int ans = 0;
Queue<int[]> queue = new LinkedList<>();
queue.add(new int[] {xs, ys});
check[xs][ys] = true;
while (!queue.isEmpty()) {
ans++;
int size = queue.size();
for (int i = 0; i < size; i++) {
int[] top = queue.poll();
for (int k = 0; k < 4; k++) {
int x = dx[k] + top[0];
int y = dy[k] + top[1];
if (x > 0 && x <= n && y > 0 && y <= m && !check[x][y] && grid[x][y] == '.') {
if (x == xt && y == yt){
System.out.println(ans);
return ;
}
queue.add(new int[] {x, y});
check[x][y] = true;
}
}
}
}
System.out.println(-1);
}
}
class Read {
StringTokenizer st = new StringTokenizer("");
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
String next() throws IOException {
while (!st.hasMoreTokens()) {
st = new StringTokenizer(bf.readLine());
}
return st.nextToken();
}
int nextInt() throws IOException {
return Integer.parseInt(next());
}
long nextLong() throws IOException {
return Long.parseLong(next());
}
}
4. 主持人调度II
题目描述

解题思路
- 把所有数组按照第一个元素排序
- 创建一个列表,表示已分配的数组。
- 放入第一个数组,接着遍历数组,如果可以与已分配的数组时间错开,就可以继续排在后面。如果与所有已分配的数组都重合,就再添加一个子列表
- 结果就是列表的长度
优化:
- 子列表中不需要存放放已分配好的数组的右端点的最大值
- 每次遍历列表时间复杂度太高,可以把列表设置成小根堆,每次与堆顶元素比较即可
代码实现
java
public int minmumNumberOfHost (int n, int[][] startEnd) {
// write code here
Arrays.sort(startEnd, (a, b)->Integer.compare(a[0], b[0]));
PriorityQueue<Integer> heap = new PriorityQueue<>();
heap.add(startEnd[0][1]);
for (int i = 1; i < n; i++) {
int top = heap.peek();
if(startEnd[i][0] >= top){
heap.poll();
heap.add(startEnd[i][1]);
}else
heap.add(startEnd[i][1]);
}
return heap.size();
}
5. 体操队形
题目描述

解题思路
DFS + 枚举
通过决策树来枚举所有情况,剪枝不合法的情况:
- 通过vis数组记录每个数字是否被使用过
- 以下面为例,2要求排在1前面,当1已经排队,2还没排队,所有情况都不可能成立,所以1先排队的情况都要剪枝。

代码实现
java
import java.util.*;
public class Main{
static boolean[] vis;
static int[] arr;
static int n = 0;
static int ret = 0;
public static void main(String[] args){
Scanner in = new Scanner(System.in);
n = in.nextInt();
arr = new int[n+1];
vis = new boolean[n+1];
for(int i = 1;i<=n;i++){
arr[i] = in.nextInt();
}
dfs(1);
System.out.println(ret);
}
static void dfs(int pos){
if(pos==n+1){
ret++;
return;
}
for(int i = 1;i<=n;i++){
if(!vis[i] && (arr[i]==i || !vis[arr[i]])){
vis[i] = true;
dfs(pos+1);
vis[i] = false;
}
}
}
}
6. 二叉树的最大路径和
题目描述

解题思路
树形dp + DFS
- 在某个子树上整合的信息:经过根节点的最大路径和
- 左子树:返回以左孩子为根节点的最大单链路径和,如果最大和是负数,可以直接舍弃
- left = Math.max(0,dfs(root.left))
- 右子树:返回以右孩子为根节点的最大单链路径和
因为最终的统计如果要包含根节点,所以左右子树的路径必须是单链,再拼接上根节点,才能得到以经过根节点的最大路径和。
每次得到的路径和中取最大值,是最终的结果.
代码实现
java
import java.util.*;
public class Solution {
int ret = -1010;
public int maxPathSum (TreeNode root) {
// write code here
dfs(root);
return ret;
}
int dfs(TreeNode root){
if(root==null)
return 0;
int left = Math.max(0,dfs(root.left));
int right = Math.max(0,dfs(root.right));
ret = Math.max(ret,left+right+root.val);
return Math.max(left,right)+root.val;
}
}
7. 排序子序列
题目描述

解题思路
贪心+模拟
定义一个指针,先判断当前是上升或者下降,如果是上升,就让指针一直向后移动到波峰,下降同理,指针不再移动时统计结果。
如果当前阶段是水平,只移动指针,不统计结果,让这段水平区域与后面上升或下降的部分连到一起
代码实现
java
import java.util.*;
import java.io.*;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) throws IOException {
Read in = new Read();
int n = in.nextInt();
int[] arr = new int[n];
for(int i= 0;i<n;i++){
arr[i] = in.nextInt();
}
int ret = 0;
int i = 0;
while(i<n){
if(i==n-1){
ret++;
break;
}
if(arr[i]<arr[i+1]){
while(i<n-1 && arr[i]<=arr[i+1])
i++;
ret++;
}else if(arr[i]>arr[i+1]){
while(i<n-1 && arr[i]>=arr[i+1])
i++;
ret++;
}else{
while(i<n-1 && arr[i]==arr[i+1])
i++;
}
i++;
}
System.out.println(ret);
}
}
class Read {
StringTokenizer st = new StringTokenizer("");
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
String next() throws IOException {
while (!st.hasMoreTokens()) {
st = new StringTokenizer(bf.readLine());
}
return st.nextToken();
}
int nextInt() throws IOException {
return Integer.parseInt(next());
}
long nextLong() throws IOException {
return Long.parseLong(next());
}
}
8. 消减整数
题目描述

解题思路
贪心
每次尽可能减去之前数的两倍:假设x-a得到y,如果y%2a==0,说明y可以一直-2a得到0;否则就-a
代码实现
java
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int t = in.nextInt();
while(t>0){
int h = in.nextInt();
h-=1;
int a = 1;
int ans = 1;
while(h>0){
if(h%(2*a)==0){
h-=2*a;
a*=2;
}else
h-=a;
ans++;
}
System.out.println(ans);
t--;
}
}
}