前言
双指针相关题解
一、盛水最多的容器
给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器。
class Solution {
public int maxArea(int[] heighet){
int a=0;
int b=heighet.length-1;
int area=0;
while (a<b){
if(heighet[a]<heighet[b]){
area=Math.max(area,heighet[a]*(b-a));
a++;
}else {
area=Math.max(area,heighet[b]*(b-a));
b--;
}
}
return area;
}
}
二、三数之和
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> ans=new ArrayList<>();
if(nums==null||nums.length<3){
return ans;
}
Arrays.sort(nums);
for (int i = 0; i < nums.length; i++) {
if(nums[i]>0){
break;
}
if(i>0&&nums[i]==nums[i-1]){
continue;
}
int a=i+1;
int b=nums.length-1;
while (a<b){
int sum=nums[i]+nums[a]+nums[b];
if(sum==0){
ans.add(Arrays.asList(nums[i],nums[a],nums[b]));
while (a<b&&nums[a]==nums[a+1]){
a++;
}
while (a<b&&nums[b]==nums[b-1]){
b--;
}
a++;
b--;
}else if(sum<0){
a++;
}else if(sum>0){
b--;
}
}
}
return ans;
}
}
三、 删除有序数组中的重复项
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
class Solution {
public int removeDuplicates(int[] nums) {
int count =1;
int a=0;
for (int i = 1; i < nums.length; i++) {
if(nums[i-1]!=nums[i]){
nums[++a]=nums[i];//若不同则添加元素
count++;
}
}
return count;
}
}
四、 实现strStr()
实现 strStr() 函数。
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1 。
//KMP
//所以前缀表具有告诉我们当前位置匹配失败,跳到之前已经匹配过的地方的能力。
class Solution {
public void getNext(int[] next, String s){
int j = -1;
next[0] = j;
for (int i = 1; i<s.length(); i++){
while(j>=0 && s.charAt(i) != s.charAt(j+1)){
j=next[j];
}
if(s.charAt(i)==s.charAt(j+1)){
j++;
}
next[i] = j;
}
}
public int strStr(String haystack, String needle) {
if(needle.length()==0){
return 0;
}
int[] next = new int[needle.length()];
getNext(next, needle);
int j = -1;
for(int i = 0; i<haystack.length();i++){
while(j>=0 && haystack.charAt(i) != needle.charAt(j+1)){
j = next[j];
}
if(haystack.charAt(i)==needle.charAt(j+1)){
j++;
}
if(j==needle.length()-1){
return (i-needle.length()+1);
}
}
return -1;
}
}
五、颜色分类
给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
class Solution {
public void sortColors(int[] nums) {
int a=0;
int b=0;
for(int i=0;i<nums.length;i++){
int num=nums[i];
nums[i]=2;
if(num<2){
nums[a++]=1;
}
if(num<1){
nums[b++]=0;
}
}
}
}
六、合并两个有序数组
给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。
class Solution {
public void merge(int[] nums1,int m,int[] nums2,int n) {
int a=0;
int b=0;
int[] nums=new int[m+n];
int ans=0;
while (a<m||b<n){
if(a==m){
ans=nums2[b];
b++;
}else if(b==n){
ans=nums1[a];
a++;
}else if(nums1[a]<nums2[b]){
ans=nums1[a];
a++;
}else {
ans=nums2[b];
b++;
}
nums[a+b-1]=ans;
}
for (int i = 0; i < nums.length; i++) {
nums1[i]=nums[i];
}
}
}
七、验证回文串
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
说明:本题中,我们将空字符串定义为有效的回文串。
class Solution {
public boolean isPalindrome(String s) {
if(s==null){
return true;
}
StringBuilder str =new StringBuilder();
for (int i = 0; i < s.length(); i++) {
Character c=s.charAt(i);
if(Character.isLetterOrDigit(c)){
str.append(Character.toLowerCase(c));
}
}
int a=0;
int b=str.length()-1;
while(a<b) {
if(str.charAt(a)!=str.charAt(b)){
return false;
}
a++;
b--;
}
return true;
}
}
八、旋转数组
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
class Solution {
public void rotate(int[] nums, int k) {
if(k>nums.length){
k=k%nums.length;}
reverse(nums,0,nums.length-1);
reverse(nums,0,k-1);
reverse(nums,k,nums.length-1);
}
private void reverse(int[] nums,int start,int end){
for (int i = start,j=end; i <j ; i++,j--) {
int tmp=nums[i];
nums[i]=nums[j];
nums[j]=tmp;
}
}
}
九、快乐数
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」定义为:
对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
如果 可以变为 1,那么这个数就是快乐数。
如果 n 是快乐数就返回 true ;不是,则返回 false
//快慢指针
class Solution {
public boolean isHappy(int n) {
int fast=getNext(n);
int slow=n;
while (fast!=slow&&fast!=1){
fast=getNext(getNext(fast));
slow=getNext(slow);
}
return fast==1;
}
private int getNext(int n){
int sum=0;
while (n>0){//n>=1
int tmp=n%10;
n=n/10;
sum+=tmp*tmp;
}
return sum;
}
}
十、移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
class Solution {
public void moveZeroes(int[] nums) {
int a=0;
int b=0;
while (b<nums.length){
if(nums[b]!=0){
swap(nums,a,b);
a++;
}
b++;
}
}
private void swap(int[] nums,int i,int j){
int tmp=nums[i];
nums[i]=nums[j];
nums[j]=tmp;
}
}
十一、反转字符串
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
class Solution {
public void reverseString(char[] s) {
int start=0;
int end=s.length-1;
for (int i = start, j = end; i < j; i++, j--) {
char tmp = s[i];
s[i] = s[j];
s[j] = tmp;
}
}
}