前缀和相关题目

2602
462
453
携程笔试题
This commit is contained in:
whai 2024-03-29 17:00:18 +08:00
parent bdd083a912
commit 2cfc6687bf
8 changed files with 755 additions and 1 deletions

View File

@ -0,0 +1,195 @@
package cn.whaifree.interview.XieChen;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/3/28 13:27
* @注释
*/
public class Xie3_13 {
static class Problem_1 {
// 游游拿到了一个字符串她想重排这个字符串后使得该字符串包含尽可能多的"you"连续子串你能帮帮她吗?
public static void main(String[] args) {
// 可以随意重排序
// 输入数据 1
// yyoouuuu
// 输出数据 1
// uyouyouu
Scanner scanner = new Scanner(System.in);
String s = scanner.next();
char[] chars = s.toCharArray();
int[] map = new int[26];
// 统计次数
for (char aChar : chars) {
map[aChar - 'a'] += 1;
}
int minLength = Math.min(map['y' - 'a'], Math.min(map['o' - 'a'], map['u' - 'a']));
map['y' - 'a'] -= minLength;
map['o' - 'a'] -= minLength;
map['u' - 'a'] -= minLength;
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[i]; j++) {
stringBuilder.append((char)('a' + i));
}
}
for (int i = 0; i < minLength; i++) {
stringBuilder.append("you");
}
System.out.println(stringBuilder.toString());
}
}
static class Problem_2{
public static void main1(String[] args) {
// 游游拿到了一个数组她每次操作可以任选一个元素加 1或者减 1
// 游游想知道将所有元素都变成和ai相等需要操作最少多少次?你需要回答ie[1,n]的结果
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] nums = new int[n];
for (int i = 0; i < n; i++) {
nums[i] = scanner.nextInt();
}
for (int num : nums) {
computeTime(nums, num);
}
}
public static void computeTime(int[] nums, int target) {
int res = 0;
for (int num : nums) {
res += Math.abs(num - target);
}
System.out.println(res);
}
/**
* 如果 要求同时+1 -1
* @param args
*/
public static void main(String[] args) {
// 游游拿到了一个数组她每次操作可以任选一个元素加 1或者减 1
// 游游想知道将所有元素都变成和ai相等需要操作最少多少次?你需要回答ie[1,n]的结果
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] nums = new int[n];
for (int i = 0; i < n; i++) {
nums[i] = scanner.nextInt();
}
// 先排序
Arrays.sort(nums);
// 对于nums内的元素遍历target
// 左边 部分+1右边部分-1直到左边活着右边全部=target时就能知道次数,检查还有多少个达不到target的
for (int i = 0; i < nums.length; i++) {
change(nums, i);
}
}
/**
* @param ints
* @param index 中间的位置
*/
public static void change(int[] ints, int index) {
// 例如 1 2 3 4 5 选取target 为3
// 统计左右距离ints[index]的数量
int leftSub = 0;
for (int i = 0; i < index; i++) {
leftSub += ints[index] - ints[i];
}
int rightSub = 0;
for (int i = index + 1; i < ints.length; i++) {
rightSub += ints[i] - ints[index];
}
System.out.println(rightSub + leftSub);
}
}
static class Problem_3{
public static void main1(String[] args) {
String input = "[1(1),2(2),-3(31),3(2222222222222222),2(12)]";
Pattern pattern = Pattern.compile("(-?\\d+)\\((-?\\d+)\\)");
Matcher matcher = pattern.matcher(input);
while (matcher.find()) {
String beforeBracket = matcher.group(1);
String insideBracket = matcher.group(2);
System.out.println("括号前的数字: " + beforeBracket + ", 括号内部的数字: " + insideBracket);
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String s = scanner.next();
List<long[]> list = new ArrayList<>();
// 正则表达式 获取s
// ()左右括号
// -?表示可选符号0或1此-
// \d 为十进制数字
// \d+ 表示\d可以出现1次或多次
// \\ \的转义
// \\( \\) 要匹配字面意义上的左括号和右括号
Pattern pattern = Pattern.compile("(-?\\d+)\\((-?\\d+)\\)");
Matcher matcher = pattern.matcher(s);
while (matcher.find()) {
String beforeBracket = matcher.group(1); // 返回给定组在上一个匹配操作期间捕获的输入子序列
String insideBracket = matcher.group(2);
list.add(new long[]{Long.parseLong(beforeBracket),Long.parseLong(insideBracket)});
}
compact(list);
}
public static void compact(List<long[]> list) {
for (int i = 1; i < list.size(); i++) {
if (list.get(i)[0] == list.get(i - 1)[0]) {
list.set(i, new long[]{i, list.get(i)[1] + list.get(i - 1)[1]});
list.remove(i - 1);
}
}
List<String> res = new ArrayList<>();
for (long[] ints : list) {
StringBuilder s1 = new StringBuilder();
s1.append(ints[0]).append("(").append(ints[1]).append(")");
res.add(s1.toString());
}
System.out.println(res.toString());
}
}
class Problem_4{
}
}

View File

@ -0,0 +1,163 @@
package cn.whaifree.interview.XieChen;
import java.util.Arrays;
import java.util.Scanner;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/3/28 19:15
* @注释
*/
public class xc328 {
static class p1{
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < n; i++) {
if (i % 2 == 0) {
stringBuilder.append("you");
}else {
stringBuilder.append("uoy");
}
}
System.out.println(stringBuilder.toString());
}
}
static class p2{
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
int[][] ints = new int[n][m];
for (int i = 0; i < n; i++) {
String[] split = in.next().split("");
for (int j = 0; j < m; j++) {
ints[i][j] = Integer.parseInt(split[j]);
}
}
// 00 变11
// 11 不变
// 10 向下走1
// 01 变11
int res = 0;
for (int i = 0; i < ints.length; i++) {
for (int j = 0; j < m - 1; j++) {
int i1 = ints[i][j];
int i2 = ints[i][j + 1];
if (i1 == 0 && i2 == 0) {
ints[i][j] = 1;
ints[i][j + 1] = 1;
res++;
} else if (i1 == 0 && i2 == 1) {
ints[i][j] = 1;
res++;
} else if (i1 == 1 && i2 == 0 && j == m - 2) {
ints[i][j] = 1;
res++;
}
}
}
System.out.println(res);
}
}
static class p3{
public static void t(int[] nums) {
}
// 将偶数的区间/2 让整个区间最大
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
long[] nums = new long[n];
for (int i = 0; i < n; i++) {
nums[i] = in.nextLong();
}
// 获取前缀和
long[] preSum = new long[n + 1];
for (int i = 1; i < n + 1; i++) {
preSum[i] = preSum[i - 1] + nums[i - 1];
}
long nowSum = 0;
long minSum = Integer.MAX_VALUE;
// 滑动窗口让窗口内的值都为偶数并且是总和最小的窗口
for (int i = 0; i < nums.length; i++) {
for (int j = i; j < nums.length; j++) {
if (Math.abs(nums[j] % 2) == 1) {
break;
}
nowSum += nums[j];
minSum = Math.min(nowSum, minSum);
}
nowSum = 0;
}
// while (right < n) {
// if (Math.abs(nums[right] % 2) == 1) {
// right++;
// left = right;
// nowSum = 0;
// continue;
// }
// nowSum += nums[right];
// while (nowSum > minSum && left < right) {
// nowSum -= nums[left];
// left++;
// }
// minSum = Math.min(nowSum, minSum);
// right++;
// }
long sum = 0;
for (long num : nums) {
sum += num;
}
System.out.println(sum - minSum / 2);
}
}
static class p4{
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] ints = new int[n];
for (int i = 0; i < n; i++) {
ints[i] = i;
}
Arrays.sort(ints);
// 1 1*2 1*2*3 1*2*3*4
for (int i = 0; i < ints.length; i++) {
pro(ints[i],i);
}
}
// 4 6 8
public static long pro(long n, long start) {
int res = 1;
for (long i = start; i < n; i++) {
res *= i;
}
return res;
}
}
}

View File

@ -2,6 +2,8 @@ package cn.whaifree.leetCode.Array;
import org.junit.Test; import org.junit.Test;
import java.util.Arrays;
/** /**
* 209. 长度最小的子数组 * 209. 长度最小的子数组
* 给定一个含有 n 个正整数的数组和一个正整数 target * 给定一个含有 n 个正整数的数组和一个正整数 target
@ -82,9 +84,45 @@ public class LeetCode209 {
} }
class Solution {
/**
* 前缀和做法
* @param target
* @param nums
* @return
*/
public int minSubArrayLen(int target, int[] nums) {
// 求前缀和
int length = nums.length;
int[] preSum = new int[length + 1];
for (int i = 1; i < preSum.length; i++) {
preSum[i] = preSum[i - 1] + nums[i - 1];
}
// 2,3,1,2,4,3
// 因为每个元素都是正数所以preSum是递增的可以用二分查找
int minLengthFillSolution = Integer.MAX_VALUE;
for (int i = 1; i < preSum.length; i++) {
// 从0开始查找
int fill = target + preSum[i - 1];
int intervalEnd = Arrays.binarySearch(preSum, fill); // 没找到就会返回负数
if (intervalEnd < 0) {
intervalEnd = -intervalEnd - 1; // 防止查出来的是负数
}
// 这个区间如果合理就可能是正常的区间
if (intervalEnd <= length)
minLengthFillSolution = Math.min(minLengthFillSolution, intervalEnd - (i - 1));
// 注意区分下标 intervalEnd和i-1 前缀和为fill和target
}
return minLengthFillSolution == Integer.MAX_VALUE ? 0 : minLengthFillSolution;
}
}
@Test @Test
public void list() { public void list() {
System.out.println(minSubArrayLen1(5, new int[]{2,3,6})); System.out.println(new Solution().minSubArrayLen(7, new int[]{2, 3, 1, 2, 4, 3}));
// System.out.println(minSubArrayLen1(5, new int[]{2,3,6}));
} }
} }

View File

@ -0,0 +1,164 @@
package cn.whaifree.leetCode.Array;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/3/28 16:59
* @注释
*/
public class LeetCode2602 {
@Test
public void test()
{
Solution solution = new Solution();
int[] nums = {3,1,6,8};
int[] queries = {1,5};
List<Long> res = solution.minOperations(nums, queries);
res.forEach(System.out::println);
}
/**
* 超时
*/
class Solution {
public List<Long> minOperations(int[] nums, int[] queries) {
List<Long> res = new ArrayList<>();
for (int query : queries) {
res.add(target(nums, query));
}
return res;
}
public long target(int[] nums, int target) {
long res = 0;
for (int num : nums) {
res += Math.abs(target - num);
}
return res;
}
}
class Solution1 {
public List<Long> minOperations(int[] nums, int[] queries) {
List<Long> res = new ArrayList<>();
Arrays.sort(nums);
// 排序后找到对应的元素左边小于右边大于
// 求前缀和
int length = nums.length;
long[] preSum = new long[length + 1];
for (int i = 0; i < length; i++) {
preSum[i + 1] = preSum[i] + nums[i];
}
for (int target : queries) {
int index = findIndex(nums, target);
long left = (long) index * target - preSum[index];
// index 为横坐标 target为纵坐标高度 preSum为index位置前面的总和
long right = preSum[length] - preSum[index] - (long) target * (length - index);
res.add(left + right);
}
// 一侧的前缀和与 平均值*一侧区间长度 就代表这一侧的总操作数
return res;
}
public int findIndex(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] > target) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return right;
}
}
@Test
public void test1()
{
Solution2 solution2 = new Solution2();
int[] nums = {3,1,6,8};
int[] queries = {5};
List<Long> res = solution2.minOperations(nums, queries);
res.forEach(System.out::println);
}
class Solution2 {
public List<Long> minOperations(int[] nums, int[] queries) {
Arrays.sort(nums);
// 计算前缀和
long[] preSum = new long[nums.length + 1];
for (int i = 1; i < preSum.length; i++) {
preSum[i] = preSum[i - 1] + nums[i - 1];
}
List<Long> res = new ArrayList<>();
for (int query : queries) {
res.add(getOperation(nums, query, preSum));
}
return res;
}
/**
* <img src="http://42.192.130.83:9000/picgo/imgs/1679808210-FVsAou-t3.png">
* </img>
* @param nums 原数组
* @param target 目标
* @param preSum 前缀和
* @return
*/
public Long getOperation(int[] nums, int target,long[] preSum) {
int index = findIndex(nums, target);
// index左边全部比他小右边全部比他大
// 0 - index 为小于他的数字个数 index-length为大于他的个数
// 小于他的数的总和 = 小于的个数 index * (target-nums[0]) - index位置的前缀和前缀和就是一个下三角形的面积
long leftIncr = (long) index * target - preSum[index];
long rightIncr =
preSum[nums.length] - preSum[index]
- (long) target * (nums.length - index);
return leftIncr + rightIncr;
}
/**
* 二分查找
* @param nums 有序数组
* @param target
* @return
*/
public int findIndex(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = (right + left) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return left;
}
}
}

View File

@ -0,0 +1,64 @@
package cn.whaifree.leetCode.Array;
import org.junit.Test;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/3/29 12:54
* @注释
*/
public class LeetCode453 {
@Test
public void test()
{
int[] nums = {1, 1,1};
int res = new Solution1().minMoves(nums);
System.out.println(res);
}
class Solution {
/**
* 让n-1个元素加1 等价于让1个元素-1直到全部元素相等
* @param nums
* @return
*/
public int minMoves(int[] nums) {
int min = Integer.MAX_VALUE;
for (int num : nums) {
min = Math.min(min, num);
}
int res = 0;
for (int num : nums) {
res += Math.abs(min - num);
}
return res;
}
}
class Solution1 {
/**
* 让n-1个元素加1 等价于让1个元素-1直到全部元素相等
* 前缀和解法
* @param nums
* @return
*/
public int minMoves(int[] nums) {
// 获取前缀和
int length = nums.length;
int[] preSum = new int[length + 1];
// 找到最小的元素的index
int minIndex = 0;
for (int i = 1; i <= length; i++) {
if (nums[minIndex] > nums[i - 1]) {
minIndex = i - 1;
}
preSum[i] = preSum[i - 1] + nums[i - 1];
}
return preSum[length] - nums[minIndex] * length;
}
}
}

View File

@ -0,0 +1,50 @@
package cn.whaifree.leetCode.Array;
import org.junit.Test;
import java.util.Arrays;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/3/29 13:15
* @注释
*/
public class LeetCode462 {
@Test
public void test()
{
Solution solution = new Solution();
int[] nums = {1,2,3};
int i = solution.minMoves2(nums);
System.out.println(i);
}
class Solution {
/**
* +1 -1
* @param nums
* @return
*/
public int minMoves2(int[] nums) {
// 排序后找到中位数
Arrays.sort(nums);
// 前缀和
int length = nums.length;
int[] preSum = new int[length + 1];
for (int i = 1; i < preSum.length; i++) {
preSum[i] = preSum[i - 1] + nums[i - 1];
}
// 中位数
int middleIndex = length / 2;
int middleValue = nums[middleIndex];
int left = middleIndex * middleValue - preSum[middleIndex];
int right = preSum[preSum.length - 1] - preSum[middleIndex] - (length - middleIndex) * middleValue;
return left + right;
}
}
}

View File

@ -0,0 +1,22 @@
package cn.whaifree.leetCode.Dynamic;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/3/28 13:15
* @注释
*/
public class LeetCode139 {
class Solution {
// public boolean wordBreak(String s, List<String> wordDict) {
// // wordDict放入s的背包
// char[] chars = s.toCharArray();
//
//
// }
}
}

View File

@ -0,0 +1,58 @@
package cn.whaifree.leetCode.Dynamic;
import org.junit.Test;
import java.util.Arrays;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/3/28 11:53
* @注释
*/
public class LeetCode279 {
@Test
public void test(){
Solution solution = new Solution();
int numSquares = solution.numSquares(12);
System.out.println(numSquares);
}
class Solution {
public int numSquares(int n) {
// 完全平方数 任意取使其满足n容量的背包的最少数量
// 给你一个整数 n 返回 和为 n 的完全平方数的最少数量
// dp[j] 表示容量为j的背包 最少 需要的 完全平方数 的数量
int[] dp = new int[n + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
// 求组合数就是外层for循环遍历物品内层for遍历背包
// 求排列数就是外层for遍历背包内层for循环遍历物品 10 01
// 本题都可以
dp[0] = 0;
// for (int j = 0; j <= n; j++) {
// for (int i = 1; i * i <= j; j++) {
// // i-j*j 表示 之前的完全平方数 + 这个挖
// dp[j] = Math.min(dp[j - i * i] + 1, dp[j]);
// }
// }
for (int i = 1; i * i <= n; i++) {
for (int j = i * i; j <= n; j++) {
// i-j*j 表示 之前的完全平方数 + 这个挖
dp[j] = Math.min(dp[j - i * i] + 1, dp[j]);
//dp[j] 可以由dp[j - i * i]推出 dp[j - i * i] + 1 便可以凑成dp[j]
// 或者说 dp[j-i*i]表示j-i*i的最小需要平方数加上我们给到的i*i这一个平方数就是+1即dp[j - i * i] + 1
}
}
return dp[n];
}
}
}