文章预览:
- 题一:给定一个未经排序的整数数组,找到最长且连续的的递增序列。
- 题二:一个长度为n-1的递增排序数组中的所有数字都是唯一的, 并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中, 请找出这个数字。
- 题三: 学校在拍年度纪念照时,一般要求学生按照 非递减 的高度顺序排列。请你返回能让所有学生以 非递减 高度排列的最小必要移动人数。注意,当一组学生被选中时,他们之间可以以任何可能的方式重新排序,而未被选中的学生应该保持不动。
- 题四:给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
- 题五:给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。
说明:从学习javase开始到如今,已经学习了接近四个月的时间了,虽然疫情让我出不了门。但是也正是疫情这个机会,让我看到了编程的“美”。体会到了编程的乐趣,五月份,跌跌撞撞简单的学完了数据结构与算法。接下来的一段时间,可能到下学期开学,都将学习框架,然后争取每天一到两道算法题。现在的学习状态感觉也到了瓶颈,处于下滑时期。加油吧,小伙子!早点调整好状态,继续前行。共勉。接下来的leetcode刷题这个小的系列,相当于我的错题本,自己能够解决的题目就不再一个一个放在上面了。
题一:给定一个未经排序的整数数组,找到最长且连续的的递增序列。
暴力解题:
- 对数组进行排序
- 遍历原数组,与排序后的数组比较,找出最长的连续序列即可
代码:
public static int getMaxLenght(int[] arr) {
if(arr.length == 0)return 0;
int count = 0;//用来存储最长的序列长度
int temp = 1;//记录当前数据的递增长度
for (int i = 0; i < arr.length - 1; i++) {
if (arr[i] < arr[i + 1]) {
temp++;
} else {
if (count < temp) count = temp ;
temp = 1;
}
}
if (temp > count) return temp ;
return count;
}
题二:一个长度为n-1的递增排序数组中的所有数字都是唯一的, 并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中, 请找出这个数字。
思路:
-
暴力解题:从数组尾部遍历,直接找出。
-
二分法
代码:
- 暴力:
public static int getMiss(int[] sums) {
if (sums.length == 1) {
if (sums[0] == 0) return 1;
else return 0;
}
int sun = sums.length;//表示最大的数字
int index = sums.length - 1;//索引
while (index >= 0) {
if (sun != sums[index]) return sun;
else sun--;
index--;
}
return -1;
}
- 二分法:
public static int getMiss2(int[] sums) {
int i = 0, j = sums.length - 1;
while (i <= j) {
int m = (i + j) / 2;
if (sums[m] == m) i = m + 1;
else j = m - 1;
}
return i;
}
题三: 学校在拍年度纪念照时,一般要求学生按照 非递减 的高度顺序排列。请你返回能让所有学生以 非递减 高度排列的最小必要移动人数。注意,当一组学生被选中时,他们之间可以以任何可能的方式重新排序,而未被选中的学生应该保持不动。
思路:
- 对表示学生身高的数组排序,得到一个排序后的新数组
- 对比排序后数组和原数组,记录下标值相同但元素值不同的下标个数,即为排错位置的学生个数
代码:
public static int getSum(int[] arr) {
int[] temp = Arrays.copyOf(arr, arr.length);
//排序
Arrays.sort(temp);
int sum = 0;
for (int i = 0; i < arr.length; i++) {
if (arr[i] == temp[i]) continue;
else sum++;
}
return sum;
}
思路二(最优思路):
- 首先我们其实并不关心排序后得到的结果,我们想知道的只是在该位置上,与最小的值是否一致 题目中已经明确了值的范围 1 <= heights[i] <= 100
- 这是一个在固定范围内的输入,比如输入: [1,1,4,2,1,3] 输入中有 3 个 1,1 个1 个 3 和 1 个 4,3 个 1 肯定会在前面,依次类推
- 所以,我们需要的仅仅只是计数而已
public static int getSum2(int[] arr) {
int[] temp = new int[101];
for (int a : arr) {
temp[a]++;
}
int count = 0;
for (int i = 0, j = 0; i < temp.length; i++) {
while (temp[i] > 0) {//说明原数组当中这索引所在的地方是有数字的
//说明位置不正确
if(arr[j++] != i)count++;
temp[i]--;
}
}
return count;
}
题四:给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
思路:
方法:双指针法
1. 数组完成排序后,我们可以放置两个指针 ii 和 jj,
其中 ii 是慢指针,而 jj 是快指针。只要 nums[i] = nums[j]nums[i]=nums[j],
我们就增加 jj 以跳过重复项。
2. 当我们遇到 nums[j]不等于nums[i] nums[j]=nums[i] 时,
跳过重复项的运行已经结束,因此我们必须把它(nums[j]nums[j])的值复制到
nums[i + 1]nums[i+1]。
然后递增 ii,接着我们将再次重复相同的过程,直到 jj 到达数组的末尾为止。
代码:
public static int getNewLenght(int[] nums) {
if (nums.length == 1 || nums.length == 0) return nums.length;
int j = 0;
for (int i = 1; i < nums.length; i++) {
if(nums[i] == nums[j]){
continue;
}else {
j++;
nums[j] = nums[i];
}
}
return j+1;
}
题五:给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。
说明:
初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。
你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。
第一思路:直接合并,然后对数组排序
代码:
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
System.arraycopy(nums2, 0, nums1, m, n);
Arrays.sort(nums1);
}
}
思路二:最直接的算法实现是将指针p1 置为 nums1的开头, p2为 nums2的开头,在每一步将最小值放入输出数组中。
代码:
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int [] nums1_copy = new int[m];
System.arraycopy(nums1, 0, nums1_copy, 0, m);
int p1 = 0;
int p2 = 0;
int p = 0;
while ((p1 < m) && (p2 < n)) nums1[p++] = (nums1_copy[p1] < nums2[p2]) ?
nums1_copy[p1++] : nums2[p2++];
if (p1 < m)
System.arraycopy(nums1_copy, p1, nums1, p1 + p2, m + n - p1 - p2);
if (p2 < n)
System.arraycopy(nums2, p2, nums1, p1 + p2, m + n - p1 - p2);
}
}