代码随想录-双指针
1.移除元素(力扣27)
1.1 题目
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/e56f0d0f8bd98ae43e093c17089c8744.png#pic_center)
1.2 代码
class Solution {
public int removeElement(int[] nums, int val) {
if(nums==null || nums.length==0){
return 0;
}
int l=0;
for(int i=0;i<nums.length;i++){
if(nums[i]!=val){
nums[l++]=nums[i];
}
}
return l;
}
}
1.3 思路
1.声明一个指向非val元素的指针l
2.将非val元素赋值到l的位置上,nums[l++]=nums[i];
3.最终的l就是非val值的数量
2.反转字符串(力扣344)
2.1 题目
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/58cae9e1e7f9542814715ce36c56cb0b.png#pic_center)
2.2 代码
class Solution {
public void reverseString(char[] s) {
int l=0;
int r=s.length-1;
while(l<=r){
char tem=s[r];
s[r]=s[l];
s[l]=tem;
l++;
r--;
}
}
}
2.3 思路
1.定义左、右两个指针,使其分别从左、右出发,进行交换
3.替换空格(剑指offer 05)
3.1 题目
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/3cafc0690be80736da849d68563e2ae6.png#pic_center)
3.2 代码
class Solution {
public String replaceSpace(String s) {
if(s==null || s.length()==1){
return s;
}
StringBuilder sb=new StringBuilder();
for(int i=0;i<s.length();i++){
if(String.valueOf(s.charAt(i)).equals(" ")){
sb.append("%20");
}else{
sb.append(s.charAt(i));
}
}
return sb.toString();
}
}
3.3 思路
使用StringBuilder,遇见空格则拼接"%20"
4.颠倒字符串中的单词(力扣151)
4.1 题目
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/6e0e52a1ac080f8c20028ba8b27a09ae.png#pic_center)
4.2 代码
class Solution {
public String reverseWords(String s) {
s=s.trim();
StringBuilder sb=new StringBuilder();
String[] strs=s.split(" ");
for(int i=strs.length-1;i>=0;i--){
if(strs[i].equals("")) continue;
sb.append(strs[i].replaceAll(" ",""));
if(i!=0){
sb.append(" ");
}
}
return sb.toString();
}
}
4.3 思路
要知道String中的以下方法:
trim():清除字符串前后的空格
split():将字符串按照某一个字符切割,返回String数组
replaceAll():将字符串中的某一个字符替换成另外一个字符
5.反转链表(力扣206)
5.1 题目
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/46a66067383068834f443288525ed2b7.png#pic_center)
5.2 代码
class Solution {
public ListNode reverseList(ListNode head) {
if(head==null || head.next==null){
return head;
}
ListNode leftNode=head;
head=head.next;
leftNode.next=null;
while(head!=null && head.next!=null){
ListNode node=head.next;
head.next=leftNode;
leftNode=head;
head=node;
}
head.next=leftNode;
return head;
}
}
5.3 思路
1.设置一个始终指向左边结点的指针,leftNode
2.head始终指向leftNode的下一个结点
3.在while中定义一个临时变量,让node=head.next
6.删除链表的倒数第N个结点(力扣19)
6.1 题目
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/f02a11cbaf70ddb059d58cda201b7ec4.png#pic_center)
6.2 代码
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
if(head==null || head.next==null){
return null;
}
ListNode fast=head;
ListNode slow=head;
for(int i=0;i<n;i++){
fast=fast.next;
}
while(fast!=null && fast.next!=null){
fast=fast.next;
slow=slow.next;
}
if(fast==null){
return head.next;
}
slow.next=slow.next.next;
return head;
}
}
6.3 思路
1.定义快慢指针slow和fast
2.先让fast走n步
2.1 当删除第一个结点时,fast为null
2.2 当删除的不是第一个结点时,fast不为null
3.让slow和fast一块走,当fast.next!=null为界限
4.若fast==null 返回head.next
若fast!=null slow.next=slow.next.next,返回head
7.链表相交(面试题 02.07)
7.1 题目
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/fb1f3ef5d983898345792387061fa860.png#pic_center)
7.2 代码(简便)
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA==null || headB==null){
return null;
}
ListNode m=headA;
ListNode n=headB;
while(m!=n){
m=(m==null)?headB:m.next;
n=(n==null)?headA:n.next;
}
return m;
}
}
7.3 代码(复杂)
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA==null || headB==null){
return null;
}
ListNode m=headA;
ListNode n=headB;
while(m.next!=null && n.next!=null){
m=m.next;
n=n.next;
}
if(m.next==null){
while(n.next!=null){
headB=headB.next;
n=n.next;
}
while(headA!=headB){
headA=headA.next;
headB=headB.next;
}
}else{
while(m.next!=null){
headA=headA.next;
m=m.next;
}
while(headA!=headB){
headA=headA.next;
headB=headB.next;
}
}
return headA;
}
}
8.环形链表Ⅱ(力扣142)
8.1 题目
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/a8edb475f3215ea7667f89906451c8c0.png#pic_center)
8.2 代码(set)
public class Solution {
public ListNode detectCycle(ListNode head) {
if(head==null || head.next==null){
return null;
}
HashSet<ListNode> set=new HashSet<>();
while(head!=null){
if(!set.contains(head)){
set.add(head);
head=head.next;
}else{
break;
}
}
return head;
}
}
8.3 代码(快慢指针)
public class Solution {
public ListNode detectCycle(ListNode head) {
if(head==null || head.next==null){
return null;
}
ListNode slow=head.next;
ListNode fast=head.next.next;
while(fast!=null && fast.next!=null){
if(slow==fast){
break;
}
slow=slow.next;
fast=fast.next.next;
}
if(fast==null || fast.next==null){
return null;
}
slow=head;
while(slow!=fast){
slow=slow.next;
fast=fast.next;
}
return slow;
}
}
8.4 思路
思路一:使用set集合
1. 当set中存在当前结点时,直接返回,说明有环
2. 当遍历完链表set中的元素都不重复,则返回null,说明无环
思路二:使用快慢指针
1. 让慢指针slow一次走一格,快指针fast一次走两格
1.1 若快指针fast==null 或 fast.next==null,则无环,直接返回null
1.2 若1.1不满足,则说明有环,执行以下程序
2.执行到这,说明有环,使慢指针slow从头开始走,快指针从当前位置走,两者都一次走一步,相遇点即为入环
9.三数之和(力扣15)
9.1 题目
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/50249b13d57b4d77ca4e2a0509c2b315.png#pic_center)
9.2 代码
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res=new ArrayList<>();
if(nums==null || nums.length<3){
return res;
}
Arrays.sort(nums);
for(int i=0;i<nums.length-1;i++){
if(i!=0 && nums[i]==nums[i-1]){
continue;
}
int l=i+1;
int r=nums.length-1;
while(r>l){
int sum=nums[i]+nums[l]+nums[r];
if(sum<0){
l++;
}else if(sum>0){
r--;
}else{
List<Integer> list=new ArrayList<>();
list.add(nums[i]);
list.add(nums[l]);
list.add(nums[r]);
res.add(list);
while(r>l && nums[l+1]==nums[l]){
l++;
}
while(r>l && nums[r]==nums[r-1]){
r--;
}
l++;
r--;
}
}
}
return res;
}
}
9.3 思路
使用三指针
1.对数组进行遍历,其中的i就是第一个指针
2.在遍历for中,指针l=i+1,r=nunms.length-1
3.内嵌循环,while(l<r),然后对其和进行判断
10.四数之和(力扣18)
10.1 题目
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/5f9953d64ccc4b27e652dbb654777f6e.png#pic_center)
10.2 代码
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> res=new ArrayList<>();
if(nums.length<4){
return res;
}
Arrays.sort(nums);
for(int i=0;i<nums.length-1;i++){
if(i!=0 && nums[i-1]==nums[i]) continue;
for(int j=i+1;j<nums.length-1;j++){
if(j>i+1 && nums[j-1]==nums[j]) continue;
int l=j+1;
int r=nums.length-1;
while(l<r){
int sum=nums[i]+nums[j]+nums[l]+nums[r];
if(sum<target){
l++;
}else if(sum>target){
r--;
}else{
List<Integer> list=new ArrayList<>();
list.add(nums[i]);
list.add(nums[j]);
list.add(nums[l]);
list.add(nums[r]);
res.add(list);
while(l<r && nums[l]==nums[l+1]){
l++;
}
while(l<r && nums[r]==nums[r-1]){
r--;
}
l++;
r--;
}
}
}
}
return res;
}
}
10.3 思路
这道题和上面的三数之和思路一样,不过要注意以下几点:
1.第一个for的i<nums.length-1,因为j=i+1
2.第二个for的j<nums.length-1,因为l=j+1
3.第二个for内,在j=i+1之后,如有nums[j-1]==nums[j],则跳过
即if(j>i+1 && nums[j]==nums[j-1]) continue;