共XX题,示例代码全部通过
– 本节题目数量:16
需要一大张纸和一个笔!!!
常用方法
System.arraycopy(newArr,0,nums,0,n);
//将newArr起始位置赋值到nums[)
二分查找法的思想在1946年提出。
第一个没有bug的二分查找法在1962年才出现
首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。
代码实现:
要明确变量含义
int binarySearch(int arr,int target){
int l = 0;
int r = arr.length-1; //区间为[0,n-1];
int mid;
while(l<=r){
//扣一个小边界是等于
mid = (l+r)/2;
if(arr[min] == target){
return target;
}else if(target > arr[mid]){
l = mid+1;//在[mid+1,r]
}else{
r = mid-1;//在[l,mid-1]
}
}
System.out.printf("不存在");
}
此时将 l 和 r 分别设置初值为0和arr.length
此时的区间为[o,arr.length)
代码实现:
int binarySearch(int arr,int target){
int l=0;
int r=arr.length; //区间为[0,n);
int mid;
while(l<r){
//此时当[x,x),此时x取不到
mid = (l+r)/2;
if(arr[mid] == target){
return mid;
}else if(target > arr[mid]){
l = mid+1;
}else{
r = mid-1;
}
}
System.out.printf("不存在");
}
小结:
如何写出正确程序
1明确变量含义
2循环不变量
3小数据量调试
T:283 Move Zeros题目链接
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
示例:
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]
思路:用一个新数组暂存
//时间复杂度 O(n)
//空间复杂度 O(n)
class Solution {
public void moveZeroes(int[] nums) {
int n = nums.length;
int[] newArr = new int[n];
int j=0;
for(int i=0;i<n;i++){
if(nums[i] != 0){
newArr[j] = nums[i];
j++;
}
}
System.arraycopy(newArr,0,nums,0,n);
}
}
双指针遍历使用赋值
在纸上画一画
用两个指针一个快的为r
当r所指的是0就移动;所指的不是0就把这个值赋给l指针;l++;r++;
//时间复杂度 O(n)
//空间复杂度 O(1)
class Solution {
public void moveZeroes(int[] nums) {
int l=0;
for(int r=0;r<nums.length;r++){
if(nums[r]!=0){
nums[l] = nums[r];
l++;
}
}
for(;l<nums.length;l++){
nums[l] = 0;
}
}
}
双指针遍历使用交换,减少空间利用
//时间复杂度 O(n)
//空间复杂度 O(1)
class Solution {
public void moveZeroes(int[] nums) {
int l=0;
for(int r=0;r<nums.length;r++){
if(nums[r]!=0){
//nums[l] = nums[r];此处交换两个数就可以了
swap(nums,l,r);
l++;
}
}
}
public void swap(int[] arr,int x,int y){
int temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
}
当都不是零的情况细节优化
//当没有零都是数的时候也可以优化
T:27题目链接
给定一个数组 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。
注意这五个元素可为任意顺序。
你不需要考虑数组中超出新长度后面的元素。
class Solution {
public int removeElement(int[] nums, int val) {
int l=0;
for(int r=0;r<nums.length;r++){
if(nums[r]!=val){
swap(nums,l,r);
l++;
}
}
return l;
}
public void swap(int[] arr,int x,int y){
int temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
}
T:26 题目链接
给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
示例 1:
给定数组 nums = [1,1,2],
函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。
你不需要考虑数组中超出新长度后面的元素。
示例 2:
给定 nums = [0,0,1,1,1,2,2,3,3,4],
函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。
你不需要考虑数组中超出新长度后面的元素。
class Solution {
public int removeDuplicates(int[] nums) {
int l=0;
Set<Integer> set = new HashSet<>();
for(int r=0;r<nums.length;r++){
if(!set.contains(nums[r])){
nums[l] = nums[r];
l++;
set.add(nums[r]);
}
}
return l;
}
}
T:80题目链接
给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素最多出现两次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
示例 1:
给定 nums = [1,1,1,2,2,3],
函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。
你不需要考虑数组中超出新长度后面的元素。
示例 2:
给定 nums = [0,0,1,1,1,1,2,3,3],
函数应返回新长度 length = 7, 并且原数组的前五个元素被修改为 0, 0, 1, 1, 2, 3, 3 。
你不需要考虑数组中超出新长度后面的元素。
图解
还是使用快慢指针
慢指针不仅指向自己的位置还指向他的上一个位置
class Solution {
public int removeDuplicates(int[] nums) {
int n = nums.length;
if(n<=2){
return n;
}
int l = 1;
for(int r=2;r<n;r++){
if(nums[l-1]!=nums[r]){
l++;
nums[l] = nums[r];
}
}
return l+1;
}
}
辅助知识:快速排序
T:75(荷兰国旗问题)题目链接
给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
注意:
不能使用代码库中的排序函数来解决这道题。示例:
输入: [2,0,2,1,1,0]
输出: [0,0,1,1,2,2]
思路1标准函数排序
class Solution {
public void sortColors(int[] nums) {
Arrays.sort(nums);
}
}
思路2三路快排一次partition
三个指针
一个用来扫描,两个用来限定范围
一个限定0的最后一个
一个限定2的第一个
一定要明确变量含义
class Solution {
public void sortColors(int[] nums) {
int l=-1;
int r=nums.length;
int i=0;//扫描用
while(i<l){
if(nums[i]==0){
l++;
i++;
}else if(nums[i]==2){
swap(nums,r-1,i);
r--;
}else{
i++;
}
}
}
public void swap(int[] arr,int x,int y){
int temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
}
T:88题目链接
给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。
说明:
初始化 nums1 和 nums2 的元素数量分别为 m 和 n。 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。
示例:
输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3输出: [1,2,2,3,5,6]
思路1
//简单思路
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
for(int i=0;m<nums1.length;m++,i++){
nums1[m] = nums2[i];
}
Arrays.sort(nums1);
}
}
思路2
//两个指针从后向前,大的加入
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int s1 = m-1;
int s2 = n-1;
int s = m+n-1;
while(s1>=0 && s2>=0){
if(nums1[s1]>nums2[s2]){
nums1[s] = nums1[s1];
s--;
s1--;
}else{
nums1[s] = nums2[s2];
s--;
s2--;
}
}
System.arraycopy(nums2,0,nums1,0,s2+1);
}
}
T:215题目链接
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
示例 1:
输入: [3,2,1,5,6,4] 和 k = 2
输出: 5示例 2:
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
思路1排序直接选
class Solution {
public int findKthLargest(int[] nums, int k) {
Arrays.sort(nums);
return nums[nums.length-k];
}
}
思路2快排思想partition
public class Solution {
public int findKthLargest(int[] nums, int k) {
int len = nums.length;
int left = 0;
int right = len - 1;
int target = len - k;
while (true) {
int index = partition(nums, left, right);
if (index == target) {
return nums[index];
} else if (index < target) {
left = index + 1;
} else {
right = index - 1;
}
}
}
public int partition(int[] nums, int left, int right) {
int pivot = nums[left];
int j = left;
for (int i = left + 1; i <= right; i++) {
if (nums[i] < pivot) {
j++;
swap(nums, j, i);
}
}
swap(nums, j, left);
return j;
}
private void swap(int[] nums, int index1, int index2) {
int temp = nums[index1];
nums[index1] = nums[index2];
nums[index2] = temp;
}
}
T:167题目链接
给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。
函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。
说明:
返回的下标值(index1 和 index2)不是从零开始的。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。示例:
输入: numbers = [2, 7, 11, 15], target = 9
输出: [1,2]
解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。
思路1:暴力双层循环
思路2:有序+二分搜索
思路3:对撞指针
附加题目:
T:125题目链接
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
说明:本题中,我们将空字符串定义为有效的回文串。
示例 1:
输入: “A man, a plan, a canal: Panama”
输出: true示例 2:
输入: “race a car”
输出: false
T:344题目链接
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
示例 1:
输入:[“h”,“e”,“l”,“l”,“o”]
输出:[“o”,“l”,“l”,“e”,“h”]示例 2:
输入:[“H”,“a”,“n”,“n”,“a”,“h”]
输出:[“h”,“a”,“n”,“n”,“a”,“H”]
T:345题目链接
编写一个函数,以字符串作为输入,反转该字符串中的元音字母。
示例 1:
输入: “hello”
输出: “holle”示例 2:
输入: “leetcode”
输出: “leotcede”
T:11题目链接
给定 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器,且 n 的值至少为 2。
图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例:
输入: [1,8,6,2,5,4,8,3,7]
输出: 49
也叫双索引技术Two Pointer,
还有一种很常用的是滑动窗口
T:209题目链接
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组。如果不存在符合条件的连续子数组,返回 0。
示例:
输入: s = 7, nums = [2,3,1,2,4,3]
输出: 2
解释: 子数组 [4,3] 是该条件下的长度最小的连续子数组。
思路1:暴力遍历所有连续子数组
思路2:滑动窗口
T:3题目链接
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。示例 2:
输入: “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。示例 3:
输入: “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
滑动窗口
T:438问题链接
给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引。
字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。
说明:
字母异位词指字母相同,但排列不同的字符串。 不考虑答案输出的顺序。
示例 1:
输入:
s: “cbaebabacd” p: “abc”输出:
[0, 6]解释:
起始索引等于 0 的子串是 “cba”, 它是 “abc” 的字母异位词。
起始索引等于 6 的子串是 “bac”, 它是 “abc” 的字母异位词。示例 2:
输入:
s: “abab” p: “ab”输出:
[0, 1, 2]解释:
起始索引等于 0 的子串是 “ab”, 它是 “ab” 的字母异位词。
起始索引等于 1 的子串是 “ba”, 它是 “ab” 的字母异位词。
起始索引等于 2 的子串是 “ab”, 它是 “ab” 的字母异位词。
T:76题目链接
给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字母的最小子串。
示例:
输入: S = “ADOBECODEBANC”, T = “ABC”
输出: “BANC”
于 0 的子串是 “cba”, 它是 “abc” 的字母异位词。
起始索引等于 6 的子串是 “bac”, 它是 “abc” 的字母异位词。
示例 2:
输入:
s: “abab” p: “ab”输出:
[0, 1, 2]解释:
起始索引等于 0 的子串是 “ab”, 它是 “ab” 的字母异位词。
起始索引等于 1 的子串是 “ba”, 它是 “ab” 的字母异位词。
起始索引等于 2 的子串是 “ab”, 它是 “ab” 的字母异位词。
T:76题目链接
给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字母的最小子串。
示例:
输入: S = “ADOBECODEBANC”, T = “ABC”
输出: “BANC”