1.二分查找(有序数组的经典查找算法)
问题:
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果 target 存在返回下标,否则返回 -1。
你必须编写一个具有 O(log n) 时间复杂度的算法。
(1)Java
java
class Solution {
public int search(int[] nums, int target) {
//避免过小过大
if(target<nums[0]|| target>nums[nums.length-1]){
return -1;
}
int left =0,right=nums.length-1;
while(left<=right){
int middle = (left+right)/2;
if(target==nums[middle]){
return middle;
}else if(target>nums[middle]){
left=middle+1;
}else if(target<nums[middle]){
right=middle-1;
}
}
return -1;
}
}
(2)JavaScript
javascript
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var search = function(nums, target) {
let l=0, r=nums.length-1;
while(l<=r){
let middle = (l+r)>>1;
if(nums[middle]==target) return middle;
let isSmall=nums[middle]>target;
l=isSmall?l:middle+1;
r=isSmall?middle-1:r;
// if(nums[middle]>target) right=middle-1;
// if(nums[middle]<target) left=middle+1;
}
return -1;
};
(3)C++
cpp
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size()-1;
while(left<=right){
int middle=(left+right)/2;
if(nums[middle]==target){
return middle;
}else if(nums[middle]>target){
right=middle-1;
}else{
left=middle+1;
}
}
return -1;
}
};
(4)Python
python
class Solution:
def search(self, nums: List[int], target: int) -> int:
left,right=0,len(nums)-1
while left<=right:
middle=(left+right)//2
if nums[middle]==target:
return middle
elif nums[middle]>target:
right=middle-1
else:
left=middle+1
return -1
1.1搜索插入位置
问题:
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。
示例 1:
输入: nums = [1,3,5,6], target = 5
输出: 2
示例 2:
输入: nums = [1,3,5,6], target = 2
输出: 1
示例 3:
输入: nums = [1,3,5,6], target = 7
输出: 4
(1)Java
java
//1、左闭右闭
class Solution {
public int searchInsert(int[] nums, int target) {
int left=0, right=nums.length-1;
while(left<=right){
// 1. 目标值等于数组中某一个元素 return mid;
int middle=(left+right)/2;
if(nums[middle]==target){
return middle;
}else if(nums[middle]>target){
right=middle-1;
}else{
left=middle+1;
}
}
// 2.目标值在数组所有元素之前 3.目标值插入数组中 4.目标值在数组所有元素之后 return right + 1;
return right+1;
}
}
//2、左闭右开
class Solution {
public int searchInsert(int[] nums, int target) {
int left=0, right=nums.length;
while(left<right){
// 1. 目标值等于数组中某一个元素 return mid;
int middle=(left+right)/2;
if(nums[middle]==target){
return middle;
}else if(nums[middle]>target){
right=middle-1;
}else{
left=middle+1;
}
}
// 2.目标值在数组所有元素之前 3.目标值插入数组中 4.目标值在数组所有元素之后 return right + 1;
return right;
}
}
(2)JavaScript
javascript
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var searchInsert = function(nums, target) {
let l=0,r=nums.length-1,ans=nums.length;
while(l<=r){
const middle = (l+r) >> 1;
if(nums[middle]>=target){
ans=middle;
r=middle-1
}else{
l=middle+1;
}
}
return ans;
};
(3)C++
cpp
//时间复杂度:O(log n)
//空间复杂度:O(1)
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int l=0,r=nums.size()-1;
while(l<=r){
int middle=(l+r)/2;
if(nums[middle]==target){
return middle;
}else if(nums[middle]>target){
r=middle-1;
}else{
l=middle+1;
}
}
return r+1;
}
};
//时间复杂度:O(n)
//空间复杂度:O(1)
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
for(int i=0;i<nums.size();i++){
if(nums[i]>=target){
return i;
}
}
return nums.size();
}
};
(4)Python
python
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
l,r=0,len(nums)-1
while l<=r:
middle=(l+r)//2
if nums[middle]==target:
return middle
elif nums[middle]>target:
r=middle-1
else :
l=middle+1
return r+1
1.2在排序数组中查找元素的第一个和最后一个位置
问题:
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
进阶:你可以设计并实现时间复杂度为 O(\\log n) 的算法解决此问题吗?
示例 1:
- 输入:nums = [5,7,7,8,8,10], target = 8
- 输出:[3,4]
示例 2:
- 输入:nums = [5,7,7,8,8,10], target = 6
- 输出:[-1,-1]
示例 3:
- 输入:nums = [], target = 0
- 输出:[-1,-1]
(1)Java
java
class Solution {
int[] searchRange(int[] nums, int target){
int leftBorder=getLeftBorder(nums,target);
int rightBorder=getRightBorder(nums,target);
if(leftBorder==-2 || rightBorder==-2) return new int[]{-1, -1};
if(rightBorder-leftBorder>1) return new int[]{leftBorder+1, rightBorder-1};
return new int[]{-1, -1};
}
int getLeftBorder(int[]nums, int target){
int l=0,r=nums.length-1;
int leftBorder=-2;
while(l<=r){
int m=l+(r-l)/2;
if(nums[m]>=target){
r=m-1;
leftBorder=r;
}else{
l=m+1;
}
}
return leftBorder;
}
int getRightBorder(int[]nums, int target){
int l=0,r=nums.length-1;
int rightBorder=-2;
while(l<=r){
int m=l+(r-l)/2;
if(nums[m]>target){
r=m-1;
}else{
l=m+1;
rightBorder=l;
}
}
return rightBorder;
}
}
(2)JavaScript
javascript
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var searchRange = function(nums, target) {
const getLeftBorder = (nums,target)=>{
let left=0,right=nums.length-1;
let leftBorder=-2;
while(left<=right){
let middle=left+(right-left)//2;
if(nums[middle]>=target){
right=middle-1;
leftBorder=right;
}else {
left=middle+1;
}
}
return leftBorder;
}
const getRightBorder = (nums,target)=>{
let left=0,right=nums.length-1;
let rightBorder=-2;
while(left<=right){
let middle=left+(right-left)//2;
if(nums[middle]>target){
right=middle-1;
}else {
left=middle+1;
rightBorder=left;
}
}
return rightBorder;
}
let leftBorder = getLeftBorder(nums,target);
let rightBorder = getRightBorder(nums,target);
if(leftBorder==-2 || rightBorder==-2) return [-1, -1];
if(rightBorder-leftBorder>1) return [leftBorder+1, rightBorder-1];
return [-1, -1];
};
(3)C++
cpp
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int leftBorder=getLeftBorder(nums,target);
int rightBorder=getRightBorder(nums,target);
if(leftBorder==-2||rightBorder==-2) return {-1, -1};
if(rightBorder-leftBorder>1) return {leftBorder+1, rightBorder-1};
return {-1, -1};
}
private:
int getLeftBorder(vector<int>& nums, int target) {
int left=0,right=nums.size()-1;
int leftBorder = -2;
while(left<=right){
int middle=(left+right)/2;
if(nums[middle]>=target){
right=middle-1;
leftBorder=right;
}else{
left=middle+1;
}
}
return leftBorder;
}
private:
int getRightBorder(vector<int>& nums, int target) {
int left=0,right=nums.size()-1;
int rightBorder=-2;
while(left<=right){
int middle=(left+right)/2;
if(nums[middle]>target){
right=middle-1;
}else{
left=middle+1;
rightBorder=left;
}
}
return rightBorder;
}
};
(4)Python
python
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
def getRightBorder(nums:List[int], target:int) -> int:
left, right = 0, len(nums)-1
rightBoder = -2 # 记录一下rightBorder没有被赋值的情况
while left <= right:
middle = left + (right-left) // 2
if nums[middle] > target:
right = middle - 1
else: # 寻找右边界,nums[middle] == target的时候更新left
left = middle + 1
rightBoder = left
return rightBoder
def getLeftBorder(nums:List[int], target:int) -> int:
left, right = 0, len(nums)-1
leftBoder = -2 # 记录一下leftBorder没有被赋值的情况
while left <= right:
middle = left + (right-left) // 2
if nums[middle] >= target: # 寻找左边界,nums[middle] == target的时候更新right
right = middle - 1
leftBoder = right
else:
left = middle + 1
return leftBoder
leftBoder = getLeftBorder(nums, target)
rightBoder = getRightBorder(nums, target)
# 情况一
if leftBoder == -2 or rightBoder == -2: return [-1, -1]
# 情况三
if rightBoder -leftBoder >1: return [leftBoder + 1, rightBoder - 1]
# 情况二
return [-1, -1]
1.3x的平方根
问题:
给你一个非负整数 x ,计算并返回 x 的 算术平方根 。
由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
注意: 不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。
(2)JavaScript
javascript
/**
* @param {number} x
* @return {number}
*/
var mySqrt = function(x) {
let find = (layer,left,right)=>{
if(right-left<=1){
return left;
}
let middle = (left+right)>>1;
if(middle*middle>x){
right=middle
}else{
left=middle;
}
return find(layer+1,left,right);
}
return find(0,1,x)
};
1.4有效的完全平方数
问题:
给你一个正整数 num 。如果 num 是一个完全平方数,则返回 true ,否则返回 false 。
完全平方数 是一个可以写成某个整数的平方的整数。换句话说,它可以写成某个整数和自身的乘积。
不能使用任何内置的库函数,如 sqrt 。
java
class Solution {
public boolean isPerfectSquare(int num) {
long l=0,r=num;
while(l<r){
long mid = l+r+1>>1;
if(mid*mid<=num) l=mid;
else r=mid-1;
}
return r*r==num;
}
}
2.移除元素(数组元素的原地修改、双指针技巧)
问题:
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
示例 1: 给定 nums = [3,2,2,3], val = 3, 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 你不需要考虑数组中超出新长度后面的元素。
示例 2: 给定 nums = [0,1,2,2,3,0,4,2], val = 2, 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。
你不需要考虑数组中超出新长度后面的元素。
(1)Java
java
// 时间复杂度:O(n^2)
// 空间复杂度:O(1)
//暴力解法:两层for循环,一个for循环遍历数组元素 ,第二个for循环更新数组
class Solution {
public int removeElement(int[] nums, int val) {
int size=nums.length;
for(int i=0;i<size;i++){
if(nums[i]==val){
for(int j=i+1;j<size;j++){
nums[j-1]=nums[j];
}
i--;
size--;
}
}
return size;
}
}
// 时间复杂度:O(n)
// 空间复杂度:O(1)
//双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。
// 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
// 慢指针:指向更新 新数组下标的位置
class Solution {
public int removeElement(int[] nums, int val) {
int slow=0;
for(int fast=0;fast<nums.length;fast++){
if(nums[fast]!=val){
nums[slow++]=nums[fast];
}
}
return slow;
}
}
(2)JavaScript
javascript
//暴力:
/**
* @param {number[]} nums
* @param {number} val
* @return {number}
*/
var removeElement = function(nums, val) {
let size=nums.length;
for(let i=0;i<size;i++){
if(nums[i]==val){
for(let j=i+1;j<size;j++){
nums[j-1]=nums[j];
}
i--;
size--;
}
}
return size;
};
//双指针
/**
* @param {number[]} nums
* @param {number} val
* @return {number}
*/
var removeElement = function(nums, val) {
let slow=0;
for(let fast=0;fast<nums.length;fast++){
if(nums[fast]!=val){
nums[slow++]=nums[fast];
}
}
return slow;
};
(3)C++
cpp
// 时间复杂度:O(n^2)
// 空间复杂度:O(1)
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int size=nums.size();
for(int i=0;i<size;i++){
if(nums[i]==val){
for(int j=i+1;j<size;j++){
nums[j-1]=nums[j];
}
i--;
size--;
}
}
return size;
}
};
// 时间复杂度:O(n)
// 空间复杂度:O(1)
// 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
// 慢指针:指向更新 新数组下标的位置
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slow=0;
for(int fast=0;fast<nums.size();fast++){
if(nums[fast]!=val){
nums[slow++]=nums[fast];
}
}
return slow;
}
};
(4)Python
python
//暴力
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
i,l=0,len(nums)
while i<l:
if nums[i]==val:
for j in range(i+1,l):
nums[j-1]=nums[j]
l-=1
i-=1
i+=1
return l
//双指针
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
slow=0
fast=0
size=len(nums)
while fast<size:
if nums[fast]!=val:
nums[slow]=nums[fast]
slow+=1
fast+=1
return slow
2.1 删除有序数组中的重复项
问题:
给你一个 非严格递增排列 的数组 nums ,请你**原地** 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。
考虑 nums 的唯一元素的数量为 k。去重后,返回唯一元素的数量 k。
nums 的前 k 个元素应包含 排序后 的唯一数字。下标 k - 1 之后的剩余元素可以忽略。
(1)Java
java
class Solution {
public int removeDuplicates(int[] nums) {
int j=0;
for(int i=0;i<nums.length;i++){
if(nums[i]!=nums[j]){
nums[++j]=nums[i];
}
}
return j+1;
}
}
(2)JavaScript
javascript
/**
* @param {number[]} nums
* @return {number}
*/
var removeDuplicates = function(nums) {
let j=0;
for(let i=0;i<nums.length;i++){
if(nums[i]!=nums[j]){
nums[++j]=nums[i]
}
}
return j+1;
};
(3)C++
cpp
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int j=0;
for(int i=0;i<nums.size();i++){
if(nums[i]!=nums[j]){
nums[++j]=nums[i];
}
}
return j+1;
}
};
(4)Python
python
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
j=0
for i in range(len(nums)):
if nums[i]!=nums[j]:
j+=1
nums[j]=nums[i]
return j+1
2.2 移动零
问题:
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
(1)Java
java
class Solution {
public void moveZeroes(int[] nums) {
int j=0;
//统计非零,将非零赋给nums[j]
for(int i=0;i<nums.length;i++){
if(nums[i]!=0){
nums[j++]=nums[i];
}
}
//从 j 开始,把后面所有位置赋值为0
for(int i=j;i<nums.length;i++){
nums[i]=0;
}
}
}
(2)JavaScript
javascript
/**
* @param {number[]} nums
* @return {void} Do not return anything, modify nums in-place instead.
*/
var moveZeroes = function(nums) {
let j=0;
//统计非零,将非零赋给nums[j]
for(let i=0;i<nums.length;i++){
if(nums[i]!=0){
nums[j++]=nums[i];
}
}
//从 j 开始,把后面所有位置赋值为0
for(let i=j;i<nums.length;i++){
nums[i]=0;
}
};
(3)C++
javascript
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int j=0;
//统计非零,将非零赋给nums[j]
for(int i=0;i<nums.size();i++){
if(nums[i]!=0){
nums[j++]=nums[i];
}
}
//从 j 开始,把后面所有位置赋值为0
for(int i=j;i<nums.size();i++){
nums[i]=0;
}
}
};
(4)Python
python
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
j=0
for i in range(len(nums)):
if(nums[i]!=0):
nums[j]=nums[i]
j+=1
for i in range(j,len(nums)):
nums[i]=0
return nums
3.有序数组的平方(数组变换 + 双指针)
问题:
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
示例 1:
- 输入:nums = [-4,-1,0,3,10]
- 输出:[0,1,9,16,100]
- 解释:平方后,数组变为 [16,1,0,9,100],排序后,数组变为 [0,1,9,16,100]
示例 2:
- 输入:nums = [-7,-3,2,3,11]
- 输出:[4,9,9,49,121]
(1)Java
java
class Solution {
public int[] sortedSquares(int[] nums) {
for(int i=0;i<nums.length;i++){
nums[i]=nums[i]*nums[i];
}
Arrays.sort(nums);
return nums;
}
}
class Solution {
public int[] sortedSquares(int[] nums) {
int r=nums.length-1;
int l=0;
int[] result = new int[nums.length];
int index=nums.length-1;
while(l<=r){
if(nums[l]*nums[l]>nums[r]*nums[r]){
result[index--]=nums[l]*nums[l];
++l;
}else{
result[index--]=nums[r]*nums[r];
--r;
}
}
return result;
}
}
(2)JavaScript
javascript
/**
* @param {number[]} nums
* @return {number[]}
*/
var sortedSquares = function(nums) {
let n=nums.length;
let result=new Array(n).fill(0);
let l=0,r=n-1,i=n-1;
while(l<=r){
if(nums[l]*nums[l]>nums[r]*nums[r]){
result[i--]=nums[l]*nums[l];
++l;
}else{
result[i--]=nums[r]*nums[r];
--r
}
}
return result;
};
(3)C++
cpp
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
//暴力排序时间复杂度是 O(n + nlogn)
for(int i=0;i<nums.size();i++){
nums[i]*=nums[i];
}
sort(nums.begin(),nums.end());
return nums;
}
};
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
//时间复杂度O(n)
int k=nums.size()-1;
vector<int> result(nums.size(),0);
for(int i=0,j=nums.size()-1;i<=j;){
if(nums[i]*nums[i]>nums[j]*nums[j]){
result[k--]=nums[i]*nums[i];
i++;
}else{
result[k--]=nums[j]*nums[j];
j--;
}
}
return result;
}
};
4.长度最小的子数组(滑动窗口 / 前缀和)
问题:
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
示例:
- 输入:s = 7, nums = [2,3,1,2,4,3]
- 输出:2
- 解释:子数组 [4,3] 是该条件下的长度最小的子数组。
提示:
- 1 <= target <= 10^9
- 1 <= nums.length <= 10^5
- 1 <= nums[i] <= 10^5
(1)Java
java
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int result = Integer.MAX_VALUE;
int sum = 0;
int i=0;
for(int j=0;j<nums.length;j++){
sum+=nums[j];
while(sum>=target){
result=Math.min(result,j-i+1);
sum-=nums[i++];
}
}
return result==Integer.MAX_VALUE?0:result;
}
}
(2)JavaScript
javascript
/**
* @param {number} target
* @param {number[]} nums
* @return {number}
*/
var minSubArrayLen = function(target, nums) {
let result = Infinity;
let sum = 0;
let i=0;
for(let j=0;j<nums.length;j++){
sum+=nums[j];
while(sum>=target){
result=Math.min(result,j-i+1);
sum-=nums[i++];
}
}
return result==Infinity?0:result;
};
(3)C++
cpp
//暴力,超时了
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
int result = INT32_MAX;
int sum = 0;
int subLength = 0;
for (int i = 0; i < nums.size(); i++) {
sum = 0;
for (int j = i; j < nums.size(); j++) {
sum += nums[j];
if (sum >= s) {
subLength = j - i + 1;
result = result < subLength ? result : subLength;
break;
}
}
}
return result == INT32_MAX ? 0 : result;
}
};
//s时间复杂度(n)
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
int result = INT32_MAX;
int sum = 0;
int sumLength = 0;
int i=0;
for(int j=0;j<nums.size();j++){
sum+=nums[j];
while(sum>=s){
sumLength=j-i+1;
result=result<sumLength?result:sumLength;
sum-=nums[i++];
}
}
return result==INT32_MAX?0:result;
}
};
5.螺旋矩阵II(数组的二维遍历、模拟)
问题:
给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
示例:
输入: 3 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ]
(1)Java
java
class Solution {
public int[][] generateMatrix(int n) {
int[][] nums=new int[n][n];
int startX=0,startY=0;
int offset=1;
int count=1;
int loop=1;
int i,j;//j表示列,i表示行
while(loop<=n/2){
//顶部
// 左闭右开,所以判断循环结束时, j 不能等于 n-offset
for(j=startY;j<n-offset;j++){
nums[startX][j]=count++;
}
// 右列
// 左闭右开,所以判断循环结束时, i 不能等于 n - offset
for(i=startX;i<n-offset;i++){
nums[i][j]=count++;
}
// 底部,从右往左
// 左闭右开,所以判断循环结束时, j != startY
for(;j>startY;j--){
nums[i][j]=count++;
}
//左列,从下往上
//左闭右开,所以判断循环结束时, i != startX
for(;i>startX;i--){
nums[i][j]=count++;
}
startX++;
startY++;
offset++;
loop++;
}
if(n%2==1){
nums[startX][startY]=count;
}
return nums;
}
}
(2)Javascript
javascript
/**
* @param {number} n
* @return {number[][]}
*/
var generateMatrix = function(n) {
let nums = new Array(n).fill(0).map(() => new Array(n).fill(0));
let startX = 0, startY = 0; // 每一圈的起始点
let offset = 1;
let count = 1; // 矩阵中需要填写的数字
let loop = Math.floor(n/2); // 记录当前的圈数
let mid = Math.floor(n/2);//中间位置
let i, j; // j 代表列, i 代表行;
while (loop--) {
// 顶部
// 左闭右开,所以判断循环结束时, j 不能等于 n - offset
for (j = startY; j < n - offset; j++) {
nums[startX][j] = count++;
}
// 右列
// 左闭右开,所以判断循环结束时, i 不能等于 n - offset
for (i = startX; i < n - offset; i++) {
nums[i][j] = count++;
}
// 底部
// 左闭右开,所以判断循环结束时, j != startY
for (; j > startY; j--) {
nums[i][j] = count++;
}
// 左列
// 左闭右开,所以判断循环结束时, i != startX
for (; i > startX; i--) {
nums[i][j] = count++;
}
startX++;
startY++;
offset++;
}
if (n % 2 == 1) { // n 为奇数时,单独处理矩阵中心的值
nums[mid][mid] = count;
}
return nums;
};
(3)C++
cpp
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>>nums(n,vector<int>(n,0));
int startX=0,startY=0;
int offset=1;
int count=1;
int loop=1;
int i,j;//j表示列,i表示行
while(loop<=n/2){
//顶部
// 左闭右开,所以判断循环结束时, j 不能等于 n-offset
for(j=startY;j<n-offset;j++){
nums[startX][j]=count++;
}
// 右列
// 左闭右开,所以判断循环结束时, i 不能等于 n - offset
for(i=startX;i<n-offset;i++){
nums[i][j]=count++;
}
// 底部,从右往左
// 左闭右开,所以判断循环结束时, j != startY
for(;j>startY;j--){
nums[i][j]=count++;
}
//左列,从下往上
//左闭右开,所以判断循环结束时, i != startX
for(;i>startX;i--){
nums[i][j]=count++;
}
startX++;
startY++;
offset++;
loop++;
}
if(n%2==1){
nums[startX][startY]=count;
}
return nums;
}
};
6.区间和(前缀和算法)
问题:
给定一个整数数组 Array,请计算该数组在每个指定区间内元素的总和。
输入描述
第一行输入为整数数组 Array 的长度 n,接下来 n 行,每行一个整数,表示数组的元素。随后的输入为需要计算总和的区间,直至文件结束。
输出描述
输出每个指定区间内元素的总和。
输入示例
5
1
2
3
4
5
0 1
1 3
输出示例
3
9
数据范围:
0 < n <= 100000
(1)Java
java
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
int n=scanner.nextInt();
int[] vec=new int[n];
int[] p=new int[n];
int presum=0;
for(int i=0;i<n;i++){
vec[i]=scanner.nextInt();
presum+=vec[i];
p[i]=presum;
}
while(scanner.hasNextInt()){
int a=scanner.nextInt();
int b=scanner.nextInt();
int sum;
if(a==0){
sum=p[b];
}else{
sum=p[b]-p[a-1];
}
System.out.println(sum);
}
scanner.close();
}
}
(2)C++
cpp
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n, a, b;
cin >> n;
vector<int> vec(n);
vector<int> p(n);
int presum = 0;
for (int i = 0; i < n; i++) {
scanf("%d", &vec[i]);
presum += vec[i];
p[i] = presum;
}
while (~scanf("%d%d", &a, &b)) {
int sum;
if (a == 0) sum = p[b];
else sum = p[b] - p[a - 1];
printf("%d\n", sum);
}
}
7.开发商购买土地(二维前缀和的实际应用)
在一个城市区域内,被划分成了n * m个连续的区块,每个区块都拥有不同的权值,代表着其土地价值。目前,有两家开发公司,A 公司和 B 公司,希望购买这个城市区域的土地。
现在,需要将这个城市区域的所有区块分配给 A 公司和 B 公司。
然而,由于城市规划的限制,只允许将区域按横向或纵向划分成两个子区域,而且每个子区域都必须包含一个或多个区块。
为了确保公平竞争,你需要找到一种分配方式,使得 A 公司和 B 公司各自的子区域内的土地总价值之差最小。
注意:区块不可再分。
【输入描述】
第一行输入两个正整数,代表 n 和 m。
接下来的 n 行,每行输出 m 个正整数。
输出描述
请输出一个整数,代表两个子区域内土地总价值之间的最小差距。
【输入示例】
3 3
1 2 3
2 1 3
1 2 3
【输出示例】
0
【提示信息】
如果将区域按照如下方式划分:
1 2 | 3
2 1 | 3
1 2 | 3
两个子区域内土地总价值之间的最小差距可以达到 0。
【数据范围】:
- 1 <= n, m <= 100;
- n 和 m 不同时为 1。
(1)Java
java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.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] = scanner.nextInt();
sum += vec[i][j];
}
}
int result = Integer.MAX_VALUE;
int count = 0; // 统计遍历过的行
// 行切分
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
count += vec[i][j];
// 遍历到行末尾时候开始统计
if (j == m - 1) {
result = Math.min(result, Math.abs(sum - 2 * count));
}
}
}
count = 0;
// 列切分
for (int j = 0; j < m; j++) {
for (int i = 0; i < n; i++) {
count += vec[i][j];
// 遍历到列末尾时候开始统计
if (i == n - 1) {
result = Math.min(result, Math.abs(sum - 2 * count));
}
}
}
System.out.println(result);
scanner.close();
}
}