leetcode数组相关
4寻找两个有序数组的中位数
思路:
- 其中一个为空的情况,利用len/2和(len-1)/2两个结果来求中位数
- 两者不为空,调用helper
- 当其中一个被筛选完,就选另一个的left + k
- 当两个数组都还有候选数字,而k减到0时,取两个数组中的left最小者
- k未到0时,分别从两者中取(k-1)/2。(考虑取第10时,相当于取第9(0开始),则9/2和(9-1)/2都是4,即取0~4共5个。取前11时,同样应该取5个,但11/2等于5,就是取6个了)当然,取值不能超过边界right。
- 判断两数组的取值中最大的哪个小,那么该组小的那部分就可以在下次调用时忽略了。新的边界要+1做调整。
int m = arr1.length;
int n = arr2.length;
if (m == 0) return (arr2[(n - 1) / 2] + arr2[(n / 2)]) / 2.0;
if (n == 0) return (arr1[(m - 1) / 2] + arr1[(m / 2)]) / 2.0;
int res1 = helper(arr1, 0, m - 1, arr2, 0, n - 1, (m + n -1) / 2);
int res2 = helper(arr1, 0, m - 1, arr2, 0, n - 1, (m + n) / 2);
return (res1 + res2) / 2.0;
// helper
if (left1 > right1) return arr2[left2 + k];
if (left2 > right2) return arr1[left1 + k];
if (k == 0) return Math.min(arr1[left1], arr2[left2]);
int newLeft1 = Math.min(left1 + (k - 1) / 2, right1); // 参考上面,这里也是-1
int newLeft2 = Math.min(left2 + (k - 1) / 2, right2);
if (arr1[newLeft1] < arr2[newLeft2]) {
return helper(arr1, newLeft1 + 1, right1, arr2, left2, right2, k - newLeft1 - 1 + left1);
} else {
return helper(arr1, left1, right1, arr2, newLeft2 + 1, right2, k - newLeft2 - 1 + left2);
11盛最多水的容器,42接雨水
11盛最多水的容器
思路:
- 设置左右指针
- 循环,只要left<right
- 计算当前最大装水量,然后较低的边界收缩。
while (left < right){
int lh = height[left], rh = height[right];
res = Math.max(res, Math.min(lh, rh) * (right - left));
if (lh < rh) left++;
else right--;
}
42接雨水
思路:
- 循环
- 计算当前最低位并移动最低位的指针
- 根据当前最低位以及过去level的最高位来确定level。(实际上level从0开始,说明level是通过lower来提高的,只要曾经出现过高的边界,那么level就不需要降低,因为已经有足够高的边界来容纳这个level)
- res累加上当前最低位与水位的差
while (right > left){
// 计算当前最低位并移动最低位的指针
int lower = height[(height[left] < height[right]) ? left++ : right--];
// 根据目前两个指针各自所遇到最高值中较小的那个值来更新可以装载的水位
// 就是木桶原理,短板决定水位,当短板高于旧水位、或者说是短板高于旧短板,水位就提高了
level = Math.max(lower, level);
// 根据当前指针的高度以及水位的差值计算该坐标下的雨水量
res += level - lower;
}
15三数之和,16最接近的三数之和,18四数之和
三数之和
思路:
排序,用来考虑可能性、后面去重和mid与right的调整
遍历
以当前数作为left,并去重
以left+1为mid,len-1为right,计算mid和right值的和,比较与left的差距,调整mid和right的位置。如果和等于left,记录left、mid和right,并调整mid和right,同时去重。
Arrays.sort(nums);
List<List<Integer>> res = new ArrayList<>();
int n = nums.length;
// 可能性,注意n == 0
if (n == 0 || nums[0] > 0 || nums[n-1] < 0) return res;
// 遍历
for (int left = 0; left < n - 2 && nums[left] <= 0; left++){
// left去重
if (left != 0 && nums[left] == nums[left - 1]) continue;
// mid、right、target变量
int mid = left + 1, right = n - 1, target = -nums[left];
// 遍历mid到right
while (mid < right){
// 大于
if (nums[mid] + nums[right] > target) right--;
// 小于
else if (nums[mid] + nums[right] < target) mid++;
// 相等,去重
else {
res.add(Arrays.asList(nums[left], nums[mid], nums[right]));
mid++;
right--;
while(mid<right && nums[mid] == nums[mid-1]) mid++;
while(mid<right && nums[right] == nums[right+1]) right--;
}
}
}
return res;
// 四数和
for (int i = 0; i < n - 3 && nums[i]*4 <= target; i++){
if (i > 0 && nums[i] == nums[i-1]) continue;
if(nums[i] + 3*nums[n-1] < target) continue;
for (int j = i + 1; j < n - 2 && nums[i] + nums[j]*3 <= target ; j++){
if (j > i + 1 && nums[j] == nums[j-1]) continue;
最接近的三数之和
思路:
- 设置closest和diff并初始化。(由于找最接近,所以只要有三个数就是必定存在的)
- 与上面类似,需要遍历(可以不考虑mid和right的去重,省事)
- 遍历开始就是判断新的和是否需要更新diff和closet,然后根据和于target的差距调整right和mid(加上sum==target的判断会快一点)
Arrays.sort(nums);
int n = nums.length;
int closest = nums[0] + nums[n/2] + nums[n-1];
int diff = Math.abs(target - closest);
for (int left = 0; left < n-2; left++){
if (left != 0 && nums[left] == nums[left-1]) continue;
int mid = left +1, right = n - 1;
while (mid < right){
int sum = nums[left] + nums[mid] + nums[right];
int newDiff = Math.abs(target - sum);
if (newDiff < diff){
diff = newDiff;
closest = sum;
}
if (sum > target) right--;
else if(sum < target) mid++;
else return target;
}
}
26/80删除排序数组中的重复项, 27移除元素
思路:
- 设置去重指针
- 遍历,从1开始
- 如果当前数与去重指针不同,去重指针的下一个就可改写为当前数的值
- 返回去重指针+1
int n = nums.length;
if (n <= 1) return n;
int p = 0; // 如果允许重复k次,p = k-1
for (int i = 1; i< n; i++){ // 如果允许重复k次,则从k开始
// 如果允许重复k次,则为num[p-k+1]
if (nums[p] != nums[i]) nums[++p] = nums[i];
}
return p + 1;
27移除元素
参考list中的移除元素,由于不确定第一个是否需要去除,所以去重指针定义为-1。其他近乎于上面一样。只不过比较的是nums[i] 与 val,而上面是num[p] 与nums[i]
int p = -1;
for(int num : nums){
if (num != val) nums[++p] = num;
}
return p + 1;
31下一个排列
思路:
- 从右往左,找出第一个小于右边的数字的index x
- 判断是否存在这个数a,如果存在,要对它进行一次交换
- 再次从右往左找第一个小于大于a的数字的index,将两个数位置交换
- reverse从index x到末尾的数字
public void nextPermutation(int[] nums) {
int n = nums.length, i = n - 2, j = n - 1;
while (i >= 0 && nums[i] >= nums[i + 1]) --i;
if (i > -1) {
while (nums[j] <= nums[i]) --j;
swap(nums, i, j);
}
reverse(nums, i+1, n-1);
}
private static void reverse(int[] nums, int startIndex, int endIndex) {
while (startIndex < endIndex) {
swap(nums, startIndex++, endIndex--);
}
}
53最大子序和
给定一个整数数组 nums
,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
思路:
- 设置res = Integer.MIN_VALUE(它是根据curSum取的)和curSum = 0 (由上述“子数组最少包含一个元素”,可以将curSum和res设为mums[0],并从1开始遍历,参考下面分治法的代码)
- 遍历
// curSum的思想是,如果当前值加上之前的累加值反而变少了,
// 那么说明之前的子序列已经比不上现在的一个数了,可以重新开始累加了。
curSum = Math.max(curSum + num, num);
res = Math.max(res, curSum);
// 分治法
public int maxSubArray(int[] nums) {
return helper(nums, 0, nums.length - 1);
}
public int helper(int[] nums, int left, int right) {
// 底层返回
// 返回left的原因是,mid是通过除法得到的,结果有可能等于left,然后调用时mid - 1就有可能得-1
// 例如 0 和 1, 9 和 10,前者mid = 0,后者 9,在调用时,只有mid-1会超出范围
if (left >= right) return nums[left];
// 找中间点,对左半边和右半边递归调用
int mid = left + (right - left) / 2;
int lmax = helper(nums, left, mid - 1);
int rmax = helper(nums, mid + 1, right);
int mmax = nums[left], msum = mmax;
for (int i = left + 1; i <= right; i++){
msum = Math.max(msum + nums[i], nums[i]);
mmax = Math.max(mmax, msum);
}
// 取左中右的最大值
return Math.max(mmax, Math.max(lmax, rmax));
}
56合并区间
思路:
- 修改interval类,实现Comparable<Interval>的compareTo
- Collections.sort(intervals)
- 先将第一个元素放进res,然后遍历
- 比较当前interval的start和res中最后一个interval的end,如果大于,说明不重叠,直接把当前interval添加到res;否则更改res最后一个interval的end为它本身end和当前interval的end之中的最大值。
res.add(intervals.get(0));
for (int i = 1; i < intervals.size(); ++i) {
Interval curInterval = intervals.get(i);
int lastIntervalEnd = res.get(res.size()-1).end;
if (lastIntervalEnd < curInterval.start) {
res.add(curInterval);
} else {
res.get(res.size()-1).end = Math.max(lastIntervalEnd, curInterval.end);
}
}
128最长连续序列
输入: [100, 4, 200, 1, 3, 2]
输出: 4
解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。
思路:题目要求O(n),所以不能用排序
- 将数据加入set
- 遍历
- 删除遍历到的数,并设置pre、next指针,分别为num-1和num+1,循环搜索并删除set中pre和next所指代的数,并不断扩大pre和next,只要指针所指代的数不存在于set,该指针就停止扩大。循环后更新maxLen = next - pre + 1
for (int num : nums) s.add(num);
for (int num : nums) {
if (s.remove(num)) {
int pre = num - 1, next = num + 1;
while (s.remove(pre)) --pre;
while (s.remove(next)) ++next;
// 注意,循环是在发现不存在时退出的,说明两个指针都多走了一步,所以下面+1-2
res = Math.max(res, next - pre - 1);
}
}
674最长连续递增序列
思路:
- 设置res记录最大值和cnt计数器
- 遍历
- 如果递增,cnt++,并更新res
- 否则重置cnt = 1
// 注意这里cnt和res的初始值
int cnt = 1, res = 1, n = nums.length;
if (n <= 1) return n;
for (int i = 1; i < n; i++) {
if (nums[i] > nums[i-1]) {
cnt++;
res = Math.max(res, cnt);
}
else cnt = 1;
}
return res;
45/55跳跃游戏
// 55能否到达终点
int n = nums.length, reach = 0;
for (int i = 0; i < n; ++i) { // 实际上能够遍历到n-1已经说明能到达终点了,下面的i > reach判断了一些不能到达终点的情况。
// i > reach 是用于跳进0的情况,此时不可能跳到最后
if (i > reach || reach >= n - 1) break;
// 不断更新当前能够到达的最远距离
reach = Math.max(reach, i + nums[i]);
}
return reach >= n - 1;
// 45假设总能到达终点
int n = nums.length, curReach = 0, preReach = 0, cnt = 0;
for (int i = 0; i < n; ++i) {
curReach = Math.max(curReach, i + nums[i]);
if (i == preReach) { // i小于preReach时更新curReach是为了确定下一步能够到达的最远距离。
preReach = curReach;
cnt++;
if (preReach >= n - 1) break;
}
}
return cnt;
41缺失的第一个正数
给定一个未排序的整数数组,找出其中没有出现的最小的正整数。
输入: [3,4,-1,1]
输出: 2
思路:
改造原数组,使得nums[0] = 1, nums[i] = i + 1。实现方法是遍历,当nums[i]所代表的数不超出数组坐标范围,而且它应该在的位置不等于它,即nums[i] != nums[nums[i] - 1]
,那么就交换,把它放到它应该在的index。遍历完就可以在遍历一次,检查哪个位置缺失了应该出现的值。如果没有,就返回n+1。
int n = nums.length;
for (int i = 0; i < n; i++){
while (nums[i] > 0 && nums[i] <= n && nums[i] != nums[nums[i] - 1]){
swap(nums, i, nums[i] - 1);
}
}
for (int i = 0; i< n; i++){
if (nums[i] != i + 1) return i + 1;
}
return n + 1;
946验证栈序列
思路:
- 新建一个栈
- 遍历
- 往栈添加push序列的元素
- 如果栈不为空,而且栈顶等于pop序列,说明需要pop(pop序列另外设置一个指针)
- 返回栈是否为空
66加一
思路:
- 设置carry=1
- 从后遍历,加carry,更新carry,判断carry是否等于1,即是否进1,是的话继续遍历,否的话就可以返回结果了。
- 如果遍历后carr等于0,说明数组只由“9”组成,返回比原数组长度大1,且res[0] = 1即可,否则返回原数组。
for (int i = n - 1; i >=0; i--){
int digit = nums[i] + carry;
nums[i] = digit % 10;
carry = digit / 10;
if (carry == 0) return nums;
}
233数字1的个数
思路:https://www.cnblogs.com/xuanxufeng/p/6854105.html
int res = 0;
for (long i = 1; i <= n; i *= 10) {
long a = n / i;
long b = n % i;
res += (a + 8) / 10 * i + (a % 10 == 1 ? b + 1 : 0);
}
return res;
84/85最大矩形
思路:
- 先说一维数组求最大矩形面积:遍历,如果下一个是大于等于当前元素的,继续。否则开始往前遍历算面积,这个过程不断更新最小高度和res。
- 扩展到二维:新建一个dp数组,根据当前值以及上一层的值来构造一维数组,并把这个数组代入上面的函数,即可计算到某一层为止的最大矩形面积。
public int maximalRectangle(char[][] matrix) {
int m = matrix.length, n = matrix[0].length;
int res = 0;
int[] dp = new int[n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
dp[j] = matrix[i][j] == '0' ? 0 : dp[j] + 1;
}
res = Math.max(res, largestRectangleArea(dp));
}
return res;
}
public int largestRectangleArea(int[] heights) {
int res = 0, n = heights.length;
for (int i = 0; i < n; i++) {
if (i + 1 < n && heights[i] <= heights[i + 1]) continue;
int minH = heights[i];
for (int j = i; j >= 0; j--) {
minH = Math.min(heights[j], minH);
int area = minH * (i - j + 1);
res = Math.max(res, area);
}
}
return res;
}
347前K个高频元素
思路:
1.HashMap + PriorityQueue
2.HashMap + 桶排
桶排,即新建一个长度为最大频率的List数组,然后遍历map,在频率index上的list添加key。最后遍历输出输出结果。
697数组的度
给定一个非空且只包含非负数的整数数组 nums
, 数组的度的定义是指数组里任一元素出现频数的最大值。
你的任务是找到与 nums
拥有相同大小的度的最短连续子数组,返回其长度。
输入: [1, 2, 2, 3, 1]
输出: 2
解释:
输入数组的度是2,因为元素1和2的出现频数最大,均为2.
连续子数组里面拥有相同度的有如下所示:
[1, 2, 2, 3, 1], [1, 2, 2, 3], [2, 2, 3, 1], [1, 2, 2], [2, 2, 3], [2, 2]
最短连续子数组[2, 2]的长度为2,所以返回2.
思路:
- 新建HashMap记录每个数字的freq和startIdx
- 遍历,更新HashMap,如果当前数字的freq等于degree,那么更新长度,如果大于degree,那么更新长度和degree
88合并两个有序数组
输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3
输出: [1,2,2,3,5,6]
思路:
- 类似合并两个有序链表,需要三个指针,两个数组各一个(从m-1和n-1开始),一个公共指针(从m+n-1开始)
- 循环,只要其中一个不为空
- 比较两个数组指针上的数谁大,大的填充到nums1[公共指针],并移动指针
- 循环,把剩余的nums2填充到nums1
1两数之和
思路:用map存储遍历过的数及其index;每次遍历检查map中是否有所需补数
217存在重复元素
思路:set
扩展
排序数组中小于0的最大数的下标和大于0的最小数的下标。二分找0。未排序:维护两个长度为2的数组,类似于找最值。
leetcode数组相关的更多相关文章
- TSPL学习笔记(4):数组相关练习
最近研究函数式编程,都是haskell和scheme交互着看的,所以笔记中两种语言的内容都有,练习一般也都用两种语言分别实现. 本篇练习一些数组有关的问题,之所以与数组相关是因为在命令式编程中以下问题 ...
- c语言中数组相关问题
c语言中数组相关问题: 1.数组基本定义: 相同数据类型的元素按一定顺序排列的集合,就是把有限个类型相同的变量用一个名字命名,然后用编号区分他们的变量的集合,这个名字称为数组名,编号称为下标.组成数组 ...
- Scala学习(三)----数组相关操作
数组相关操作 摘要: 本篇主要学习如何在Scala中操作数组.Java和C++程序员通常会选用数组或近似的结构(比如数组列表或向量)来收集一组元素.在Scala中,我们的选择更多,不过现在我们先假定不 ...
- PHP基础系列(二) PHP数组相关的函数分类整理
之前写过一篇介绍 PHP字符串函数 的博文,这里写第二篇,本文主要介绍PHP 数组相关的函数: 一.检查数组中是否存在 array_key_exists — 检查给定的键名或索引是否存在于数组中 ar ...
- 快学Scala习题解答—第三章 数组相关操作
3 数组相关操作 3.1 编写一段代码.将a设置为一个n个随机整数的数组,要求随机数介于0(包括)和n(不包括)之间 random和yield的使用 import scala.math.rando ...
- leetcode tree相关题目总结
leetcode tree相关题目小结 所使用的方法不外乎递归,DFS,BFS. 1. 题100 Same Tree Given two binary trees, write a function ...
- [LeetCode] [链表] 相关题目总结
刷完了LeetCode链表相关的经典题目,总结一下用到的技巧: 技巧 哑节点--哑节点可以将很多特殊case(比如:NULL或者单节点问题)转化为一般case进行统一处理,这样代码实现更加简洁,优雅 ...
- Leetcode数组题*3
目录 Leetcode数组题*3 66.加一 题目描述 思路分析 88.合并两个有序数组 题目描述 思路分析 167.两数之和Ⅱ-输入有序数组 题目描述 思路分析 Leetcode数组题*3 66.加 ...
- LeetCode 数组分割
LeetCode 数组分割 LeetCode 数组怎么分割可以得到左右最大值的差值的最大 https://www.nowcoder.com/study/live/489/1/1 左右最值最大差 htt ...
随机推荐
- c++和python如何实现主机字节序和网络字节序的相互转换
在上一篇文章网络编程:主机字节序和网络字节序中,介绍了主机字节序和网络字节序的基本概念以及在实际的编程中,何时需要进行网络字节序和主机字节序的转换.本篇文章着重介绍使用c++和python语言,如何实 ...
- LVS部分调度算法的适应场景分析
1.轮叫调度算法(RR)假设所有服务器处理性能均相同,不管服务器的当前连接数和响应速度.该算法相对简单,不适用于服务器组中处理性能不一的情况,而且当请求服务时间变化比较大时,轮叫调度算法容易导致服务器 ...
- 深入理解Three.js(WebGL)贴图(纹理映射)和UV映射
本文将详细描述如何使用Three.js给3D对象添加贴图(Texture Map,也译作纹理映射,“贴图”的翻译要更直观,而“纹理映射”更准确.).为了能够查看在线演示效果,你需要有一个兼容WebGL ...
- querySelector
this.el.nativeElement.querySelector import {Component, ElementRef, OnInit} from '@angular/core';
- centos vm 桥接 --网络配置
/etc/sysconfig/network-scripts/ifcfg-eth0 DEVICE=eth0 BOOTPROTO=none BROADCAST=192.168.1.255 HWADDR= ...
- CAD动态绘制样条线(com接口)
主要用到函数说明: _DMxDrawX::SendStringToExecuteFun 把命令当着函数执行,可以传参数.详细说明如下: 参数 说明 IDispatch* pParam 命令参数,IMx ...
- Python - 面对对象(进阶)
目录 Python - 面对对象(进阶) 类的成员 一. 字段 二. 方法 三. 属性 类的修饰符 类的特殊成员 Python - 面对对象(进阶) 类的成员 一. 字段 字段包括:普通字段和静态字段 ...
- https://github.com/MediaTek-Labs/linkit-smart-7688-feed编译失败
mkdir -p /home/fly/workdir/LinkltSmart7688Duo-20170626/openwrt/dl/home/fly/workdir/LinkltSmart7688Du ...
- Accessoft-日期区间段查询示例,开始日期至截止日期区段查询
Accessoft-日期区间段查询示例,开始日期至截止日期区段查询 实现功能效果如下: 示例查询开始日期为2017年3月15日到2017年3月16日的内容: sql查询语句如下: SELECT Inf ...
- 洛谷 P1972 BZOJ 1878 [SDOI2009]HH的项链
题目描述 HH 有一串由各种漂亮的贝壳组成的项链.HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义.HH 不断地收集新的贝壳,因此,他的项链变得越来越长. ...