977 有序数组的平方
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
思路:双指针法,一个指向头元素,一个指向尾元素。从尾元素开始放数据
class Solution {
public int[] sortedSquares(int[] nums) {
int tail = nums.length - 1;
int head = 0;
//存放在一个新的数组里
int[] result = new int[nums.length];
int index = result.length - 1;
while (head <= tail) {
if (nums[head] * nums[head] > nums[tail] * nums[tail]) {
result[index--] = nums[head] * nums[head];
++head;
} else {
result[index--] = nums[tail] * nums[tail];
--tail;
}
}
return result;
}
}
209 长度最小的子数组
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
思路:滑动窗口思想。这道题建议自己手动画图理解一下。感觉也有点像双指针的用法。
for循环内是尾指针end,需要遍历数组内的元素。为什么不选头指针在for循环内是因为头指针遍历完后,尾指针还是需要再遍历一遍,跟暴力拆解法没有区别
public class MinSubTest {
public int minSubTest(int[] nums,int target){
int sum = 0;
//需要取一个最大值,只有是最大值的时候,才能不断去更新
int result = Integer.MAX_VALUE;
int start = 0;
for (int end = 0; end < nums.length; end++) {
//存放滑动窗口元素的值
sum += nums[end];
while(sum >= target){
/**
* 获取最小值
* end-start+1 是滑动窗口的长度
*/
result = min(result,end-start+1);
//当sum >= target的时候,向右移动 故需要减去头指针位置上的值
sum -= nums[start++];
}
}
return result==Integer.MAX_VALUE?0:result;
}
}
59 螺旋矩阵||
给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
思路:这道题一定要画图,边界要找好。遵循循环不变量
class Solution {
public int[][] generateMatrix(int n) {
int[][] arr = new int[n][n];
int count = 1; //矩阵中需要填写的数字
int loop = 1; //循环的次数
int startx = 0,starty = 0;
int offset = 1; //偏移量
int i,j;
while(loop <= n/2){
for(j = starty;j<n-offset;j++){
arr[startx][j] = count++;
}
for(i = startx;i<n-offset;i++){
arr[i][j] = count++;
}
for(;j>starty;j--){
arr[i][j] = count++;
}
for(;i>startx;i--){
arr[i][j] = count++;
}
startx++;
starty++;
loop++;
offset++;
}
//中间最后一圈的时候的处理
if(n%2==1){
arr[startx][starty] = count;
}
return arr;
}
}
58 区间和
给定一个整数数组 Array,请计算该数组在每个指定区间内元素的总和。
输入描述
第一行输入为整数数组 Array 的长度 n,接下来 n 行,每行一个整数,表示数组的元素。随后的输入为需要计算总和的区间,直至文件结束。
输出描述
输出每个指定区间内元素的总和。
思路:前缀和。前缀和的思想是重复利用计算过的子数组之和,从而降低区间查询需要累加计算的次数。
public class PreAdd {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
//整数数组的长度
int n = input.nextInt();
int[] vec = new int[n];
int[] preAdd = new int[n];
int preSum = 0; //前缀和
for (int i = 0; i < n; i++) {
vec[i] = input.nextInt();
preSum += vec[i];
preAdd[i] = preSum;
}
while (input.hasNextInt()) {
int intervalStart = input.nextInt(); //第一个区间
int intervalEnd = input.nextInt(); //第二个区间
int sum;
if (intervalStart == 0) {
sum = preAdd[intervalEnd];
} else {
sum = preAdd[intervalEnd] - preAdd[intervalStart - 1];
}
System.out.println(sum);
}
input.close();
}
}
44 开发商购买土地
在一个城市区域内,被划分成了n * m个连续的区块,每个区块都拥有不同的权值,代表着其土地价值。目前,有两家开发公司,A 公司和 B 公司,希望购买这个城市区域的土地。
现在,需要将这个城市区域的所有区块分配给 A 公司和 B 公司。
然而,由于城市规划的限制,只允许将区域按横向或纵向划分成两个子区域,而且每个子区域都必须包含一个或多个区块。
为了确保公平竞争,你需要找到一种分配方式,使得 A 公司和 B 公司各自的子区域内的土地总价值之差最小。
注意:区块不可再分。
输入描述
第一行输入两个正整数,代表 n 和 m。
接下来的 n 行,每行输出 m 个正整数。
输出描述
请输出一个整数,代表两个子区域内土地总价值之间的最小差距。
输入示例
3 3 1 2 3 2 1 3 1 2 3
输出示例
0
public class DeveloperLord {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
//n*m个连续的区块
int n = input.nextInt(); //行
int m = input.nextInt();//列
int sum = 0;
int[][] vec = new int[n][m];
//遍历二维数组
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
vec[i][j] = input.nextInt();
sum += vec[i][j];; //所有土地面积之和
}
}
//统计横向的和
int[] horizontal = new int[n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
horizontal[i] += vec[i][j];
}
}
//统计纵向的和
int[] vertical = new int[m];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
vertical[i] +=vec[j][i];
}
}
//初始化结果变量为最大整数值,用于后续更新为最小值
int result = Integer.MAX_VALUE;
int horizaontalCut = 0; //横向切割线左侧的面积和
for (int i = 0; i < n; i++) {
horizaontalCut += horizontal[i];
result = Math.min(result,Math.abs(sum-2*horizaontalCut));
}
int verticalCut = 0; // 纵向切割线左侧的面积和
for (int i = 0; i < m; i++) {
verticalCut += vertical[i];
result = Math.min(result,Math.abs(sum-2*verticalCut));
}
System.out.println(result);
}
}