122. 大数减法
题目描述
以字符串的形式读入两个数字,编写一个函数计算它们的差,以字符串形式返回。
输入描述
输入两个数字(都为正数)
输出描述
两个输入数字的差
输入示例
1 2
输出示例
-1
提示信息
输入的数据可能会超出一般长整数的范围。
模拟。
import java.util.*;
class Main{
public static void main (String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
String[] nums = s.split(" ");
String num1 = nums[0], num2 = nums[1];
int num1Length = num1.length(), num2Length = num2.length();
if(num1Length > num2Length){
System.out.println(compute(num1, num2));
}else if(num1Length < num2Length){
System.out.println("-" + compute(num2, num1));
}else{
for(int i = 0; i < num1Length; i++){
int a = num1.charAt(i) - '0';
int b = num2.charAt(i) - '0';
if(a > b){
System.out.println(compute(num1, num2));
break;
}else if(a < b){
System.out.println("-" + compute(num2, num1));
break;
}else if(i == num1Length - 1){
System.out.println("0");
}
}
}
}
public static String compute(String num1, String num2){
StringBuilder sb = new StringBuilder();
int num1Length = num1.length(), num2Length = num2.length();
int indexOfNum1 = num1Length - 1, indexOfNum2 = num2Length - 1;
int mod = 0;
for(; indexOfNum1 >= 0 && indexOfNum2 >= 0; indexOfNum1--, indexOfNum2--){
int n1 = num1.charAt(indexOfNum1) - '0';
int n2 = num2.charAt(indexOfNum2) - '0';
int ans = n1 + mod >= n2 ? n1 + mod - n2 : 10 + n1 + mod - n2;
mod = n1 + mod >= n2 ? 0 : -1;
sb.append(ans);
}
while(indexOfNum1 >= 0){
int n1 = num1.charAt(indexOfNum1) - '0';
int ans = n1 + mod >= 0 ? n1 + mod : 10 + n1 + mod;
mod = n1 + mod >= 0 ? 0 : -1;
sb.append(ans);
indexOfNum1--;
}
String res = sb.reverse().toString();
int right = 0;
while(right < res.length()){
if(res.charAt(right) == '0'){
right++;
}else{
break;
}
}
return res.substring(right);
}
}
如果是笔试,可以直接利用java.math.BigInteger
快速求解:
import java.util.*;
import java.math.*;
class Main{
public static void main(String[] arg){
Scanner sc = new Scanner(System.in);
String[] nums = sc.nextLine().split(" ");
System.out.println(new BigInteger(nums[0]).add(new BigInteger("-" + nums[1])));
}
}
123. 滑动窗口最大值
题目描述
给定一个整数数组 nums 和一个整数 k,k 表示滑动窗口的大小。
你需要找出每个滑动窗口中的最大值与最小值的差,并返回这些差的最大值。
输入描述
数组的长度为 n,1 <= n <= 10000,数组中的每个元素范围为[-10000,10000],
滑动窗口大小k的范围为[1,n]。
输出描述
例如,给定一个字符串 "nums = [1,3,-1,-3,5,3,6,7], k = 3",表示一个数组和窗口大小 k。
对于该数组中的每个窗口,计算最大值与最小值的差,并返回这些差值中的最大值。
在这个例子中,每个窗口的最大值与最小值的差分别为 [4, 6, 8, 8, 3, 4],因此最终返回的结果是 8。
输入示例
nums = [1,3,-1,-3,5,3,6,7], k = 3
输出示例
8
提示信息
题目输入是一个字符串,需要自己解析为数组和 k 值。
leetcode239题变形,采用两个PriorityQueue即可,注意数据的读取。
import java.util.*;
class Main{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
String numsStr = str.substring(str.indexOf("[") + 1, str.indexOf("]"));
String[] numsArr = numsStr.split(",");
int[] nums = new int[numsArr.length];
for (int i = 0; i < numsArr.length; i++) {
nums[i] = Integer.parseInt(numsArr[i].trim());
}
int k = Integer.parseInt(str.substring(str.lastIndexOf("=") + 1).trim());
System.out.println(maxSlidingWindow(nums, k));
}
public static int maxSlidingWindow(int[] nums, int k){
PriorityQueue<int[]> maxQueue = new PriorityQueue<>(new Comparator<int[]>(){
public int compare(int[] pair1, int[] pair2){
return pair1[0] != pair2[0] ? pair2[0] - pair1[0] : pair2[1] - pair1[1];
}
});
PriorityQueue<int[]> minQueue = new PriorityQueue<>(new Comparator<int[]>(){
public int compare(int[] pair1, int[] pair2){
return pair1[0] != pair2[0] ? pair1[0] - pair2[0] : pair1[1] - pair2[1];
}
});
int n = nums.length;
for(int i = 0; i < k; i++){
maxQueue.offer(new int[]{nums[i], i});
minQueue.offer(new int[]{nums[i], i});
}
int res = maxQueue.peek()[0] - minQueue.peek()[0];
for(int i = k; i < n; i++){
maxQueue.offer(new int[]{nums[i], i});
minQueue.offer(new int[]{nums[i], i});
while(maxQueue.peek()[1] <= i - k){
maxQueue.poll();
}
while(minQueue.peek()[1] <= i - k){
minQueue.poll();
}
res = Math.max(res, maxQueue.peek()[0] - minQueue.peek()[0]);
}
return res;
}
}
117. 软件构建
题目描述
某个大型软件项目的构建系统拥有 N 个文件,文件编号从 0 到 N - 1,
在这些文件中,某些文件依赖于其他文件的内容,这意味着如果文件 A 依赖于文件 B,
则必须在处理文件 A 之前处理文件 B (0 <= A, B <= N - 1)。
请编写一个算法,用于确定文件处理的顺序。
输入描述
第一行输入两个正整数 N, M。表示 N 个文件之间拥有 M 条依赖关系。
后续 M 行,每行两个正整数 S 和 T,表示 T 文件依赖于 S 文件。
输出描述
输出共一行,如果能处理成功,则输出文件顺序,用空格隔开。
如果不能成功处理(相互依赖),则输出 -1。
输入示例
5 4
0 1
0 2
1 3
2 4
输出示例
0 1 2 3 4
提示信息
文件依赖关系如下:
所以,文件处理的顺序除了示例中的顺序,还存在
0 2 4 1 3
0 2 1 3 4
等等合法的顺序。
数据范围:
0 <= N <= 10 ^ 5
1 <= M <= 10 ^ 9
每行末尾无空格。
思路:就是leetcode210:课程表II的原题,换了个名词而已,直接bfs拓扑排序。
import java.util.*;
class Main{
public static void main (String[] args) {
Scanner sc = new Scanner(System.in);
int numOfFiles = sc.nextInt();
int connections = sc.nextInt();
List<Integer>[] arr = new List[numOfFiles];
for (int i = 0; i < numOfFiles; i++){
arr[i] = new ArrayList<>();
}
int[] indegree = new int[numOfFiles];
for(int i = 0; i < connections; i++){
int a = sc.nextInt();
int b = sc.nextInt();
arr[a].add(b);
indegree[b]++;
}
int index = 0;
int[] res = new int[numOfFiles];
Deque<Integer> queue = new LinkedList<>();
for(int i = 0; i < numOfFiles; i++){
if(indegree[i] == 0){
queue.offer(i);
}
}
while(!queue.isEmpty()){
int fileRoot = queue.poll();
res[index++] = fileRoot;
for(int file : arr[fileRoot]){
indegree[file]--;
if(indegree[file] ==0){
queue.offer(file);
}
}
}
if(index == numOfFiles){
for(int i = 0; i < numOfFiles; i++){
if(i != numOfFiles - 1){
System.out.print(res[i] + " ");
}else{
System.out.print(res[i]);
}
}
}
else{
System.out.println("-1");
}
}
}
124. 小红的数组构造
题目描述
小红的数组构造小红希望你构造一个数组满足以下条件:
1. 数组共有 n 个元素,且所有元素两两不相等。
2. 所有元素的最大公约数等于 k。
3. 所有元素之和尽可能小。请你输出数组元素之和的最小值。
输入描述
两个正整数 n 和 k。
输出描述
一个正整数,代表数组元素之和的最小值。
输入示例
3 1
输出示例
6
提示信息
数据范围: 1≤ n,k ≤ 10^5
思路:最大公约数为
k
k
k,那就是说这些数是
k
,
2
k
,
3
k
,
⋯
,
n
k
k,2k,3k,\cdots, nk
k,2k,3k,⋯,nk,直接等差数列求和得到答案,注意要用long
类型,不要越界。
import java.util.*;
class Main{
public static void main (String[] args) {
Scanner sc = new Scanner(System.in);
long n = sc.nextInt();
long k = sc.nextInt();
System.out.println((k*n*(n+1)/2));
}
}
125. 精华帖子
题目描述
小红书的推荐帖子列表为 [0 ,n),其中所有的帖子初始状态为 “普通”,现在运营同学把其中的一些帖子区间标记为了 “精华”。
运营同学选择了固定长度 k,对整个帖子列表截取,要求计算在固定的截取长度 k 下,能够截取获得的最多精华帖子数量。
输入描述
第一行输入三个正整数 n,m,k,分别代表初始帖子列表长度,精华区间的数量,以及运营同学准备截取的长度。
接下来的 m 行,每行输入两个正整数,li 和 ri ,代表第 i 个左闭右开区间。
1 <= k <= n <= 20000000.
1 <= m <= 100000.
0 <= li < ri <= n,保证任意两个区间是不重复的。
输出描述
一个正整数,代表截取获得的最多的精华帖子数量。
输入示例
5 2 3
1 2
3 5
输出示例
2
提示信息
这是一个长度为 5 的帖子列表,如果用 0 表示普通帖子,1 表示精华帖子,则该列表为 [0, 1, 0, 1, 1],用长度 k = 3 的区间截取列表,最多能够包含两个精华帖子。
思路:可以用滑动窗口进行解决,空间会比较紧张。
import java.util.*;
class Main{
public static void main (String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(), m = sc.nextInt(), k = sc.nextInt();
int[][] intervals = new int[m][2];
for(int i = 0; i < m; i++){
intervals[i][0] = sc.nextInt();
intervals[i][1] = sc.nextInt();
}
Arrays.sort(intervals, (interval1, interval2) -> interval1[0] - interval2[0]);
int res = 0, sum = 0;
int left = 0, right = 0;
while(right < m){
sum += intervals[right][1] - intervals[right][0];
while(intervals[right][1] - intervals[left][1] >= k){
//当左边区间不被滑动窗口包含时
sum -= intervals[left][1] - intervals[left][0];
left++;
}
if(intervals[right][1] - intervals[left][0] > k){
//左边区间只有部分被滑动窗口包围
res = Math.max(res, sum - (intervals[right][1] - k - intervals[left][0]));
}else{
res = Math.max(res, sum);
}
right++;
}
System.out.println(res);
}
}
126. 连续子数组最大和
题目描述
小红拿到了一个数组,她希望进行最多一次操作:将一个元素修改为x。小红想知道,最终的连续子数组最大和最大是多少?
输入描述
第一行输入一个正整数t,代表询问次数。
对于每次询问,输入两行:
第一行输入两个正整数n和x。代表数组的大小,以及小红可以修改成的元素。
第二行输入n个正整数a_i,代表小红拿到的数组
输出描述
输出 t 行,每行输出一个整数,代表连续子数组的最大和。
输入示例
3
5 10
5 -1 -5 -3 2
2 -3
-5 -2
6 10
4 -2 -11 -1 4 -1
输出示例
15
-2
15
提示信息
例如输入:
6 10
4 -2 -11 -1 4 -1
可以用10 替换 -11,连续子数组的最大和:4 -2 10 -1 4,总和为:15
数据范围:
1 ≤ t ≤ 100000
1 ≤ n ≤ 200000
-10^9 ≤ x ,a_i ≤ 10^9
每组所有询问的n的和不超过200000。
由于最多只能改变一次值,所以我们可以用一个replacePre变量记录改变后的最大值。
思路:动态规划,
p
r
e
i
pre_i
prei记录的是不考虑替换的以第 i 个数结尾的「连续子数组的最大和」,所以:
p
r
e
i
=
m
a
x
{
p
r
e
i
−
1
+
n
u
m
s
i
,
n
u
m
s
i
}
pre_i=max\{pre_{i-1}+nums_i,nums_i\}
prei=max{prei−1+numsi,numsi}
如果没有替换这个条件就可以直接res = max{res, pre}
了,所以接下来还需要考虑替换的情况,那就是令
r
e
p
l
a
c
e
P
r
e
replacePre
replacePre表示考虑替换的以第 i 个数结尾的「连续子数组的最大和」,所以:
r
e
p
l
a
c
e
P
r
e
i
=
m
a
x
{
r
e
p
l
a
c
e
N
u
m
b
e
r
,
p
r
e
i
−
1
+
r
e
p
l
a
c
e
N
u
m
b
e
r
,
r
e
p
l
a
c
e
P
r
e
i
−
1
+
n
u
m
s
i
}
replacePre_i=max\{replaceNumber,pre_{i-1}+replaceNumber,replacePre_{i-1}+nums_i\}
replacePrei=max{replaceNumber,prei−1+replaceNumber,replacePrei−1+numsi}
第一个元素表示直接拿替换的数字作为起点,重新开始记录;
第二个元素表示未替换过的最大值加上需要替换的数字;
第三个元素表示替换过的最大值加上正常的数字。
三个元素都保证了replacePre这个变量记录的是替换后的「连续子数组的最大和」。至于没有替换的情况,那就是上面
p
r
e
pre
pre考虑的情况了。
import java.util.*;
class Main{
public static void main (String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
while(n > 0){
int len = sc.nextInt();
int replace = sc.nextInt();
int[] nums = new int[len];
for (int i = 0; i < len; i++){
nums[i] = sc.nextInt();
}
int pre = 0, replacePre = pre, res = nums[0];
for(int num : nums){
replacePre = Math.max(replace, Math.max(replace + pre, replacePre + num));
pre = Math.max(num, num + pre);
res = Math.max(res, Math.max(pre, replacePre));
}
System.out.println(res);
n--;
}
}
}