1.移动元素
描述
小明获得了一个仅包含正整数且每个元素各不相同的数组,显然数组里存在最大值与最小值。小明每次能够交换两个相邻的数字,他想知道,将最大值与最小值分别移动到数组两端,最少需要交换多少次?
输入输出
输入: 第一行输入一个正整数n,数组元素的个数。
接下来一行为n个各不相同的正整数,第i个数代表数组内第i个元素(1≤i≤n)。
1≤n≤10^5
1≤a_i≤1e9
**输出:**一个正整数,代表最少需要交换的次数。
示例:
输入:
5
4 5 3 1 2
输出:
2
思路
首先,我们需要找到数组中的最大值和最小值,以及它们的位置。
然后,我们需要将最大值和最小值移动到数组的两端。这里有两种可能的情况:一种是将最大值移动到数组的左端,最小值移动到数组的右端;另一种是将最小值移动到数组的左端,最大值移动到数组的右端。我们需要计算出这两种情况下的交换次数,然后取最小的那个。
对于第一种情况,我们需要将最大值移动到数组的左端,最小值移动到数组的右端。这需要的交换次数为pos1 +(n-1)-pos2
。其中,pos1是最大值的位置,pos2是最小值的位置,n是数组的长度。
对于第二种情况,我们需要将最小值移动到数组的左端,最大值移动到数组的右端。这需要的交换次数为pos2 +(n-1)-pos1
。
代码
package stu.lbc.algorithm.code.writtentest;
import java.util.Scanner;
//
//小明获得了一个仅包含正整数且每个元素各不相同的数组,显然数组里存在最大值与最小值。
// 小明每次能够交换两个相邻的数字,他想知道,将最大值与最小值分别移动到数组两端,最少需要交换多少次?
//第一行输入一个正整数n,数组元素的个数。
//接下来一行为n个各不相同的正整数,第i个数代表数组内第i个元素(1≤i≤n)。
//输出一个正整数,代表最少需要交换的次数。
public class Baidu01_MovingElements {
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
int n= in.nextInt();
int[] nums=new int[n];
for (int i = 0; i < n; i++) {
nums[i]=in.nextInt();
}
int max=0,min=Integer.MAX_VALUE,maxIndex=0,minIndex=0;
for (int i = 0; i < n; i++) {
if (max<nums[i]){
max=nums[i];
maxIndex=i;
}
if (min>nums[i]){
min=nums[i];
minIndex=i;
}
}
int res_1=maxIndex+(n-1)-minIndex;
int res_2=minIndex+(n-1)-maxIndex;
System.out.println(Math.min(res_1,res_2));
}
}
2.有向图的节点
描述
给定一个有向图,一共有n个节点以及n条边,问:从1号节点出发,k步之内能够到达哪些节点?
输入输出
输入:
第一行两个整数n,k,表示节点的数量,以及最多走的步数
第二行n个整数a_i,表示从i到a_i 有一条有向边
输出:
能到达的节点的编号,按从小到大的顺序输出。
示例:
输入:
5 100
5 4 5 2 3
输出:
1 3 5
思路
题目要求从1号节点出发,k步之内能够到达哪些节点。这是一个典型的图遍历问题,我们可以使用广度优先搜索(BFS)来解决。
首先,我们需要创建一个队列,将1号节点放入队列,并将其标记为已访问。
然后,我们开始进行BFS。在每一轮中,我们首先获取当前队列的大小,这个大小就是当前步数可以到达的节点数量。然后,我们遍历这些节点,对于每一个节点,我们将其所有未访问过的邻居节点放入队列,并将这些邻居节点标记为已访问。在这个过程中,我们需要记录当前的步数,如果步数达到k,我们就停止遍历。
代码
//给定一个有向图,一共有n个节点以及n条边,问:从1号节点出发,k步之内能够到达哪些节点?
//第一行两个整数n,k,表示节点的数量,以及最多走的步数
//第二行n个整数a_i,表示从i到a_i 有一条有向边
//能到达的节点的编号,按从小到大的顺序输出。
public class Baidu02_DirectedGraphNodes {
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
int n=in.nextInt();
long k=in.nextLong();
//保存有向图
LinkedList<Integer>[] graph=new LinkedList[n+1];
//记录已访问的节点
boolean[] vis=new boolean[n+1];
//记录访问的节点,从小到达
ArrayList<Integer> res=new ArrayList<>();
//初始化有向图
Arrays.setAll(graph,e->new LinkedList<>());
for (int i = 1; i <= n; i++) {
//得到节点
int node=in.nextInt();
//记录点i可以访问的节点
graph[i].add(node);
}
//广度搜索
ArrayDeque<Integer> queue=new ArrayDeque<>();
//第一个节点先入堆
vis[1]=true;
queue.offer(1);
res.add(1);
long depth=0;
while (!queue.isEmpty()){
int sz=queue.size();
depth++;
for (int i=0;i<sz;++i){
int t=queue.poll();
for(int x:graph[t]){
if (!vis[x]&&depth<k){
vis[x]=true;
queue.offer(x);
res.add(x);
}
}
}
}
Collections.sort(res);
System.out.println(res);
}
}
3.小李移瓶子
描述
小李初始位于 ( a , b ) (a,b) (a,b)位置,二维平面上有个瓶子,每个瓶子的位置为 ( x i , y i ) (x_i,y_i) (xi,yi),小李每次可以 向上、下、左、右移动一格,每次移动的代价为1,小李需要每次移动到一个瓶子的位置上,然后拿起瓶子把它放到 ( c , d ) (c,d) (c,d)位置,每次最多只能拿一个瓶子。请问最少需要多少代价才能把所以瓶子都放到 ( c , d ) (c,d) (c,d)位置上。
输入输出
输入:
第一行四个整数a,b,c,d(-109<=a,b,c,d<=109)表示小塔初始位置和瓶子需要放置的位置。
接下来一行一个整数n(1<=n<=105)表示瓶子的数量。
接下来n行,每行两个整数
x
i
,
y
i
x_i,y_i
xi,yi(-109<=
x
i
,
y
i
x_i,y_i
xi,yi<=109)表示第i个瓶子的位置。
输出:
输出一个整数,表示最少需要多少代价。
示例:
输入:
0 0 1 1
2
1 0
2 2
输出:
6
思路
除了第一次从 ( a , b ) (a,b) (a,b)出发外,后面均是从 ( c , d ) (c,d) (c,d)出发再回到 ( c , d ) (c,d) (c,d),所以需要确定我们去的第一个点是哪个。枚举该点并计算其它点到的路径总和即可。
代码
//小塔初始位于$(a,b)$位置,二维平面上有个瓶子,每个瓶子的位置为$(x_i,y_i)$,小塔每次可以 向上、下、左、右移动一格,每次移动的代价为1,
// 小塔需要每次移动到一个瓶子的位置上,然后拿起瓶子把它放到$(c,d)$位置,每次最多只能拿一个瓶子。
// 请问最少需要多少代价才能把所以瓶子都放到$(c,d)$位置上。
//第一行四个整数a,b,c,d(-10^9^<=a,b,c,d<=10^9^)表示小塔初始位置和瓶子需要放置的位置。
//接下来一行一个整数n(1<=n<=10^5^)表示瓶子的数量。
//接下来n行,每行两个整数$x_i,y_i$(-10^9^<=$x_i,y_i$<=10^9^)表示第i个瓶子的位置。
public class Meituan01_MovesTheBottle {
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
int a=in.nextInt();
int b=in.nextInt();
int c=in.nextInt();
int d=in.nextInt();
int n=in.nextInt();
int min=Integer.MAX_VALUE;
int ans=0;
for (int i = 0; i < n; i++) {
//点的坐标
int x=in.nextInt();
int y=in.nextInt();
//得到从瓶子所在到目标点的距离
int t=Math.abs(x-c)+Math.abs(y-d);
//记录从目标点到瓶子所在处再返回
ans+=2*t;
//计算从(a,b)到当前点的距离减去从(c,d)到当前点的距离目的是为了找到离起始点最近的瓶子
//从而确定我们一开始去哪个点
int dist=Math.abs(x-a)+Math.abs(y-b)-t;
if (dist<min){
min=dist;
}
}
System.out.println(ans+min);
}
}
4.小李算数
描述
小李有三个数字 a , b , c a,b,c a,b,c他每次操作可以选择一个数字将其加一,最多可以操作 k k k次,小李想知道 a ∗ b ∗ c a*b*c a∗b∗c的最大值是多少?由于这个数字可能很大,因此你需要输出答案对 1 0 9 + 7 10^9+7 109+7取模后的结果。
输入输出
输入:
第一行四个整数a,b,c,k(1<=a,b,c,d<=1018)表表示数字和操作次数。
输出:
输出一个整数表示答案
示例:
输入:
1 2 3 1
输出:
12
思路
很简单的思想,想让乘积最大则每次都让三个数中的最小值+1
代码
import java.util.Arrays;
import java.util.Scanner;
//小李有三个数字$a,b,c$他每次操作可以选择一个数字将其加一,最多可以操作$k$次,
// 小李想知道$a*b*c$的最大值是多少?由于这个数字可能很大,因此你需要输出答案对$10^9+7$取模后的结果。
//第一行四个整数a,b,c,k(1<=a,b,c,d<=10^18^)表表示数字和操作次数。
//输出一个整数表示答案
public class Meituan01_XiaoLiArithmetic {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
//使用long接收
long[] nums=new long[3];
nums[0] = sc.nextLong();
nums[1] = sc.nextLong();
nums[2] = sc.nextLong();
long k= sc.nextLong();
long mod=1000000007;
//对其排序
Arrays.sort(nums);
//得到最大值和其他数的差值,即三个数都等于最大值需要加1的次数
long needed=(nums[2]-nums[0])+(nums[2]-nums[1]);
//如果加1的次数大于差值则剩余三者均分
if (k>=needed){
//k减完差值后还剩的次数
k-=needed;
//三者先均分
nums[0]+=k/3;
nums[1]+=k/3;
nums[2]+=k/3;
//均分后剩下的值
//判断是剩下多少后再分
long reminder=k%3;
if (reminder==1){
nums[0]+=1;
}else{
nums[0]+=1;
nums[1]+=1;
}
//如果k小于needed
}else {
//如果k不够让最小值等于第二小的值则先给最小的加
if (k<=nums[1]-nums[0]){
nums[0]+=k;
}else {
//如果够则先将最小值大小加到第二小同等大小后均分
nums[0]=nums[1];
k-=(nums[1]-nums[0]);
nums[0]+=k/2+k%2;
nums[1]+=k/2;
}
}
long res=((nums[0])%mod)*((nums[1])%mod)*((nums[2])%mod);
System.out.println(res);
}
}