数组矩阵类 LeeCode数据结构题库
Solution11盛最多水的容器、Solution283移动零、Solution169多数元素、Solution724寻找数组的中心下标、Solution1013将数组分成和相等的三个部分、Solution74搜索二维矩阵、Solution240搜索二维矩阵Ⅱ、Solution209长度最小的子数组、Solution905按奇偶排序数组、
摩尔投票法,前缀和法,寻找切割点,滑动窗口
Solution11盛最多水的容器
给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
选择排序比较,非常慢时间复杂度超出限制
public int maxArea(int[] height) {
int maxArea = 0;
for (int i = 0; i < height.length - 1; i++) {
for (int j = i + 1; j < height.length; j++) {
int area = Math.min(height[i],height[j]) * (j - i);
maxArea = Math.max(area,maxArea);
}
}
return maxArea;
}
双指针法 时间复杂度On
想法:往后或往前试长度的时候可以把小于当前最开始的值当作标尺,比更长的还要矮就可以直接跳过,每次用math.max挑选出来。
public int maxArea(int[] height) {
int maxArea = 0;
int l = 0;
int r = height.length - 1;
while (l < r) {
if (height[l] <= height[r]){
int low = height[l];
int area = low * (r - l);
maxArea = Math.max(area,maxArea);
while (l < r && height[l] <= low){
l++;
}
}else {
int low = height[r];
int area = low * (r - l);
maxArea = Math.max(area,maxArea);
while (l < r && height[r] <= low){
r--;
}
}
}
return maxArea;
}
Solution169多数元素
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
排序法直接排序找中间值,中间值必是众数
public int majorityElement(int[] nums) {
Arrays.sort(nums);
return nums[nums.length/2];
}
摩尔投票法
public int majorityElement(int[] nums) {
int count = 1;
int m = nums[0];
for(int i = 1; i < nums.length; i++) {
if(nums[i] == m) {
count++;
}else {
count--;
if (count == 0){
m = nums[i];
count = 1;
}
}
}
return m;
}
Solution283移动零
给定一个数组
nums
,编写一个函数将所有0
移动到数组的末尾,同时保持非零元素的相对顺序。
插入排序 元素稳定 但是时间复杂度为On*2
public class S283移动零 {
public void moveZeroes(int[] nums) {
for (int i = 0; i < nums.length; i++) {
if (nums[i] != 0){
for (int j = i; j > 0 && nums[j - 1] == 0; j--){
int temp = nums[j];
nums[j] = nums[j - 1];
nums[j - 1] = temp;
}
}
}
}
}
双指针法 快且稳
public void moveZeroes01(int[] nums) {
int k = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] != 0){
int temp = nums[i];
nums[i] = nums[k];
nums[k] = temp;
k++;
}
}
}
}
Solution724寻找数组的中心下标
给你一个整数数组 nums ,请计算数组的 中心下标 。
数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。
如果中心下标位于数组最左端,那么左侧数之和视为 0 ,因为在下标的左侧不存在元素。这一点对于中心下标位于数组最右端同样适用。
如果数组有多个中心下标,应该返回 最靠近左边 的那一个。如果数组不存在中心下标,返回 -1 。
前缀和法
遍历总和,右边就等于总和减左边和,从0开始计数左边和与右边和相等即可 。
public int pivotIndex(int[] nums) {
int sum = 0;
for(int num : nums) {
sum += num;
}
int leftSum = 0;
int rightSum = 0;
for (int i = 0; i < nums.length; i++) {
if (i == 0) {
leftSum = 0;
}else {
leftSum += nums[i - 1];
}
rightSum = sum - leftSum - nums[i];//当前数右边
if (leftSum == rightSum){
return i;
}
}
return -1;
}
Solution1013将数组分成和相等的三个部分
给你一个整数数组 arr,只有可以将其划分为三个和相等的 非空 部分时才返回 true,否则返回 false。
形式上,如果可以找出索引 i + 1 < j 且满足 (arr[0] + arr[1] + ... + arr[i] == arr[i + 1] + arr[i + 2] + ... + arr[j - 1] == arr[j] + arr[j + 1] + ... + arr[arr.length - 1]) 就可以将数组三等分。
找切割点,3整除数组总和,找到一个和就切一下,找到第二组定位第三组。
public boolean canThreePartsEqualSum(int[] arr) {
int sum = 0;
for (int num : arr){
sum += num;
}
if (sum % 3 != 0){
return false;
}
int key = sum / 3;
int i = 0;
int part = 0;
while (i < arr.length) {
part += arr[i];
if (part == key){//等于就强制退出
break;
}
i++;
}
if (part != key) {//没有就返回false
return false;
}
part = 0;
//找第二组定位第三组
int j = i + 1;
while (j < arr.length - 1){//第三组至少有一个元素存在
part += arr[j];
if (part == key) {//第二组找到就不找第三组
return true;
}
j++;
}
return false;
}
双指针法
public boolean canThreePartsEqualSum01(int[] arr) {
int sum = 0;
for (int num : arr){
sum += num;
}
if (sum % 3 != 0){
return false;
}
int key = sum / 3;
int left = 0;
int leftSum = arr[left];
int right = arr.length - 1;
int rightSum = arr[right];
while (left + 1 < right){//左小于右的情况下找到第一组和第三组
if (leftSum == key && rightSum == key){
return true;
}
if (leftSum != key){
leftSum += arr[++left];
}
if (rightSum != key){
rightSum += arr[--right];
}
}
return false;
}
Solution74搜索二维矩阵
编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:
每行中的整数从左到右按升序排列。
每行的第一个整数大于前一行的最后一个整数。
将二维数组换算成一维数组进行判断,除列与对列取余,然后用二分查找。
public boolean searchMatrix(int[][] matrix, int target) {
int R = matrix.length;
int C = matrix[0].length;
int left = 0;
int right = R * C - 1;
int mid = (left + right) / 2;
while (true) {
if (matrix[mid / C][mid % C] < target){
left = mid + 1;
} else if (matrix[mid / C][mid % C] > target){
right = mid - 1;
}else {
return true;
}
if (left > right ){//越界则没有
return false;
}
mid = (left + right) / 2;//每次都要重置mid
}
}
Solution240搜索二维矩阵Ⅱ
编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性:
每行的元素从左到右升序排列。
每列的元素从上到下升序排列。第一行右边不一定比第二行左边大,无法展开成一维数组。
从矩阵左下角往右上走去找,往上一定小往右一定大。
public boolean searchMatrix(int[][] matrix, int target) {
//设长宽,起始在左下
int row = matrix.length;
int col = matrix[0].length;
int x = row - 1;
int y = 0;
while (true){
if (x<0 || y >= col){
return false;
}
//大了往上走 小了往右走
if (matrix[x][y] > target){
x--;
}else if (matrix[x][y] < target){
y++;
}else {
return true;
}
}
}
Solution209长度最小的子数组
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
滑动窗口法本质还是双指针法,小于目标后标后扩,满足目标让前标延后。
public int minSubArrayLen(int s, int[] nums) {
int left = 0;
int right = 0;
int sum = nums[right];
int length = 0;
int minLength = nums.length;
while (true) {
if (sum < s) {
if (++right >= nums.length){
break;
}
sum +=nums[right];
}else {
length = right - left + 1;
minLength = minLength < length ? minLength : length;
sum -= nums[left];
left++;
if (left > right){
break;
}
}
}
if (length == 0) return 0;//防止没找到用初始值验证
return minLength;
}
Solution905按奇偶排序数组
给定一个非负整数数组
A
,返回一个数组,在该数组中,A
的所有偶数元素之后跟着所有奇数元素。你可以返回满足此条件的任何数组作为答案
选择排序 交换奇偶 时间复杂度较高
public int[] sortArrayByParity(int[] nums) {
for (int i = 0; i < nums.length; i++) {
if (nums[i] % 2 == 1){
for (int j = i + 1; j < nums.length; j++) {
if (nums[j] % 2 == 0) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
break;
}
}
}
}
return nums;
}
双指针法 前后同时移动
public int[] sortArrayByParity01(int[] A) {
int l = 0;
int r = A.length - 1;
while (l < r) {
//左奇右偶直接换
if (A[l] % 2 == 1 && A[r] % 2 == 0){
int temp = A[l];
A[l] = A[r];
A[r] = temp;
}else if (A[l] % 2 == 0 && A[r] % 2 == 1){
//左偶右奇指针都动
l++;
r--;
}else if (A[l] % 2 == 1 && A[r] % 2 == 1){
r--;
}else {
l++;
}
}
return A;
}