题目1: 删除有序数组中的重复项
力扣
https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/
题目描述:给你一个 升序排列 的数组 nums
,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。
输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。
class Solution {
public int removeDuplicates(int[] nums) {
/**
* 先判断边界条件
**/
if(nums==null || nums.length == 0){
return 0;
}
if(nums.length == 1){
return 1;
}
//定义两个指针
int j = 0; //快指针,往后找到和i值不一样的地方
int i = 0; //慢指针,等待互换的地方
while(j<nums.length){
if(nums[j] != nums[i]){
nums[i+1] = nums[j];
i++;
}
j++; // 如果nums[i]==nums[j], j就往后走,直到nums[i]!=nums[j],把j换到i+1的位置
}
return i+1; //最后数组的length比i大1
}
}
题目2: 最长连续递增序列
力扣https://leetcode-cn.com/problems/longest-continuous-increasing-subsequence/
题目描述:给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。
输入:nums = [1,3,5,4,7]
输出:3
解释:最长连续递增序列是 [1,3,5], 长度为3。
尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为 5 和 7 在原数组里被 4 隔开。
class Solution {
public int findLengthOfLCIS(int[] nums) {
int len = nums.length;
int res = 0; //目前,最长连续递增序列的长度
int i = 0; //慢指针, 指向递增序列的头
int j = 0;//快指针, 指向递增序列的尾
while(j<len){
//因为是递增序列,所以异常条件就是nums[前一位] >= nums[后一位]
if(j>0 && nums[j-1] >= nums[j]){
i = j;
}
// 把异常条件排除后, 剩下的就是可以正常比较的了
j++;
res = Math.max(res, j-i);
}
return res;
}
}
题目3: 移除元素
力扣https://leetcode-cn.com/problems/remove-element/ 题目描述:
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,4,0,3]
解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。
class Solution {
public int removeElement(int[] nums, int val) {
if(nums == null || nums.length==0){
return 0;
}
int len = nums.length ; //指向数组尾部的指针
int i = 0; //从前往后循环的指针
while(i<len){
if(nums[i] == val){ // 因为不考虑数组的顺序, 所以当有val的时候,从数组末尾拿个数过来补位就可以
nums[i] = nums[len-1];
len--;
}else{
i++;
}
}
return len;
}
}
题目4: 删除排序数组中的重复项 II
力扣https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array-ii/题目描述:给你一个有序数组
nums
,请你 原地 删除重复出现的元素,使每个元素 最多出现两次 ,返回删除后数组的新长度。
输入:nums = [0,0,1,1,1,1,2,3,3]
输出:7, nums = [0,0,1,1,2,3,3]
解释:函数应返回新长度 length = 7, 并且原数组的前五个元素被修改为 0, 0, 1, 1, 2, 3, 3 。 不需要考虑数组中超出新长度后面的元素。
class Solution {
public int removeDuplicates(int[] nums) {
if(nums == null || nums.length==0){
return 0;
}
if(nums.length <=2){
return nums.length;
}
int slow = 2;
int fast = 2;
while(fast<nums.length){
//因为有序数组,所以fast只需要和slow的前两位比较即可
if(nums[slow-2] != nums[fast]){
nums[slow] = nums[fast];
slow ++;
}
fast++;
}
return slow;
}
}
题目3和题目4 的区别:
题目三为无序数组,可以使用头指针和尾指针, 相互交换
题目四为有序数组,需要快慢指针,进行比较和交换
题目5: 移动零
力扣https://leetcode-cn.com/problems/move-zeroes/题目描述:给定一个数组
nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。请注意 ,必须在不复制数组的情况下原地对数组进行操作。
输入: nums = [0,1,0,3,12] 输出: [1,3,12,0,0]
/**第一版本,很乱
**/
public void moveZeroesFirst(int[] nums) {
int i = 0;
int j = 1;
while (j < nums.length && i < nums.length) {
if (nums[i] == 0) {
while (nums[j] == 0 && j + 1 < nums.length) {
j++;
}
int temp = nums[j];
nums[j] = nums[i];
nums[i] = temp;
i++;
j++;
} else {
i++;
j++;
}
}
}
/**第二版本
* if和else中相同的内容可以拿出来
**/
public void moveZeroesSecond(int[] nums) {
int i = 0;
int j = 1;
while (j < nums.length && i < nums.length) {
if (nums[i] == 0) {
while (nums[j] == 0 && j + 1 < nums.length) {
j++;
}
int temp = nums[j];
nums[j] = nums[i];
nums[i] = temp;
}
i++;
j++;
}
}
/**第三版本
* 换了个判断条件,就清楚多了
**/
public void moveZeroesThird(int[] nums) {
int i = 0;
int j = 0;
while (j < nums.length) {
if (nums[j] != 0) {
int temp = nums[j];
nums[j] = nums[i];
nums[i] = temp;
i++;
}
j++;
}
}
题目6: 盛水最多的容器盛最多水的容器
https://leetcode-cn.com/problems/container-with-most-water/
题目描述: 给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。 说明:你不能倾斜容器。
输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
public int maxArea(int[] height) {
if(height.length < 2){
return 0;
}
/**
* 面积=长*宽, 所以要保证左右两边尽可能长, 最小值尽可能大
*/
int left = 0; //最左开始
int right = height.length-1; //最右开始
int area = 0;
while (left< right){
area = Math.max(area,Math.min(height[left],height[right]) * (right-left));
if(height[left]<=height[right]){ // 短的一个边往前移,试图找到长一点的边
left++;
}else{
right--;
}
}
return area;
}