【代码随想录】双指针

27. 移除元素

在这里插入图片描述

class Solution {
    public int removeElement(int[] nums, int val) {
        if(nums==null || nums.length==0){
            return 0;
        }
        int i=0;
        for(int j=0; j<nums.length; j++){
            if(nums[j]!=val){
                nums[i++]=nums[j];
            }
        }
        return i;
    }
}

344. 反转字符串

在这里插入图片描述

class Solution {
    public void reverseString(char[] s) {
        for(int i=0,j=s.length-1; i<j; i++,j--){
            char temp=s[i];
            s[i]=s[j];
            s[j]=temp;
        }
    }
}

54. 替换数字

在这里插入图片描述

import java.util.*;
public class Main{
    public static void main (String[] args) {
        Scanner scanner = new Scanner(System.in);
        String str = scanner.next();
        //String不可变,StringBuilder可变
        StringBuilder sb = new StringBuilder();
        for(int i=0;i<str.length();i++){
            char ch = str.charAt(i);
            if(ch>='0' && ch<='9'){
                sb.append("number");
            }else{
                sb.append(ch);
            }
        }

        System.out.println(sb);
    }
}

151. 翻转字符串里的单词

在这里插入图片描述
不额外开辟空间的做法比较繁琐,没做

206. 反转链表

在这里插入图片描述
在这里插入图片描述

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        if(head==null){
            return null;
        }
        ListNode pre=null;
        ListNode current=head;
        while(current!=null){
            ListNode post=current.next;
            current.next=pre;
            pre=current;
            current=post;
        }
        return pre;
    }
}

19.删除链表的倒数第N个节点

在这里插入图片描述

快慢指针解法:

  • 开始时 fast 指针和 slow 指针都指向 head 节点(第 1 个节点)
  • 然后,slow 不动,fast 指针先走
  • 等到某一轮循环 fast 走到第 n+2 个节点时,那么在本轮循环 slow 就可以开始走了。本轮循环结束时,fast 走到第 n+2 个节点,slow 走到第 2 个节点,于是 fast 比 slow 快 n 步
  • 此后的每一轮循环,fast 和 slow 同时前走一个节点,即 fast 一直比 slow 快 n 步
  • 这样,当 fast 为 null(最后一个节点的后面)时,slow 就指向倒数第 n 个节点
    在这里插入图片描述
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        if(head==null){
            return null;
        }
        ListNode preHead=new ListNode(0,head);
        int i=1;
        ListNode preSlow=preHead;
        ListNode fast=head, slow=head;
        while(fast!=null){   
            fast=fast.next;
            i++;      
            if(i>n+1){//本轮fast走了n+2,slow还停在1,所以slow要开始出动了
                slow=slow.next;
                preSlow=preSlow.next;
            }
        }
        preSlow.next=slow.next;
        return preHead.next;
    }
}

160. 链表相交

在这里插入图片描述

快慢指针解法:先统计两个链表的长度,如果两个链表的长度不一样,就让链表长的先走,直到两个链表长度一样,这个时候两个链表再同时每次往后移一步,看节点是否一样,如果有相等的,说明这个相等的节点就是两链表的交点,否则如果走完了还没有找到相等的节点,说明他们没有交点,直接返回 null

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if(headA==null || headB==null){
            return null;
        }
        int lengthA=listLength(headA);
        int lengthB=listLength(headB);

        ListNode longP=null;
        ListNode shortP=null;
        int lengthAB=-1;

        if(lengthA>lengthB){
            longP=headA;
            shortP=headB;
            lengthAB=lengthA-lengthB;
        }else{
            longP=headB;
            shortP=headA;
            lengthAB=lengthB-lengthA;
        }

        // 让长度长的链表指针先走lengthAB步
        int i=0;
        while(i<lengthAB){         
            longP=longP.next;
            i++;
        }//此循环结束时,longP指向编号为lengthAB的节点(编号从0开始),即第lengthAB+1个节点
        //而shortP还指向head节点也就是第1个节点,所以此时两者离链表尾的距离相同了

        while(longP!=null){
            if(longP==shortP){
                return longP;
            }
            longP=longP.next;
            shortP=shortP.next;
        }
        return null;
    }
    private int listLength(ListNode head){
        ListNode pointer=head;
        int length=0;
        while(pointer!=null){
            length++;
            pointer=pointer.next;
        }
        return length;
    }
}

142. 环形链表II

在这里插入图片描述

快慢指针解法,先说结论:

  • 快指针每次走 2 步,慢指针每次走 1 步
  • 若链表无环,一直等到快指针走到链表尾部,快慢指针也不会相遇
  • 若链表有环,快指针一定会在将来与慢指针重合,该位置记为 meet
    • 链表开始位置记为 start,则 start 与入环点的距离 == meet 与入环点的距离。
    • 此时,meet 和 start 同时前进,二者一定会在入环点相遇,返回该入环点即可

(关于上面结论的证明在这篇文章:https://blog.csdn.net/Claffic/article/details/129431980)

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode detectCycle(ListNode head) {
        if(head==null){
            return null;
        }
        ListNode fast=head;
        ListNode slow=head;
        while(fast!=null&&fast.next!=null){
            fast=fast.next.next;
            slow=slow.next;
            if(fast==slow){//找到相遇点了
                //start与meet同时前进,一定会遇到两者重合的点,就是入环的第一个节点
                ListNode meet=fast;
                ListNode start=head;
                while(meet!=start){
                    meet=meet.next;
                    start=start.next;
                }
                return meet;
            }
        }
        // 如果fast走到null了,说明链表无环
        return null;
    }
}

15. 三数之和

在这里插入图片描述
在这里插入图片描述

双指针解法:

  • 首先将数组排序
  • for 循环遍历数组,i 从下标 0 的地方开始,定义 left 在 i+1 的位置,right 在数组结尾的位置
  • 在数组中找到 nums[i]、nums[left]、nums[right] 使得三者之和为 0,若找到 left++,right–
  • 如果nums[i] + nums[left] + nums[right] > 0,说明三数之和大了,因为数组经过了排序,所以 right–
  • 如果 nums[i] + nums[left] + nums[right] < 0 说明三数之和小了,left++,才能让三数之和大一些
  • 重复上面三步操作,直到 left 与 right 相遇,i 再指向下一个数组元素。

在本解法中,去重操作统一交给了 Set 集合,执行用时较长,但能过,且省去许多考虑。

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        if(nums==null || nums.length<3){
            return null;
        }

        Arrays.sort(nums);

        Set<List<Integer>> set = new HashSet<>();
        for(int i=0;i<nums.length-2;i++){
            int left=i+1;
            int right=nums.length-1;
            while(left<right){
                int sum=nums[i]+nums[left]+nums[right];
                if(sum==0){
                    set.add(geneSorted(nums[i], nums[left], nums[right]));
                    left++;
                    right--;
                }else if(sum<0){
                    left++;
                }else{
                    right--;
                }  
            }
        }
        return new ArrayList<>(set);
    }
    // 传入三个整数,返回三个整数构成的List集合,集合中的元素是升序排列的
    private List<Integer> geneSorted(int a, int b, int c){
        List<Integer> list=new ArrayList<>();
        list.add(a);
        list.add(b);
        list.add(c);
        Collections.sort(list);
        return list;
    }
}

18. 四数之和

在这里插入图片描述

<think>好的,我现在需要处理用户关于查找“代码随想录”相关资源或内容的请求。用户提到了算法题解、数据结构和学习笔记。首先,我应该回顾用户提供的引用内容,看看哪些引用与代码随想录相关。 查看引用部分,引用[1]、[3]、[4]都提到了代码随想录。引用[1]详细介绍了代码随想录在LeetCode题目讲解中的系统性和学习路径,包括学习顺序和资源链接。引用[3]提供了具体的算法实现示例,如有效字母异位词和赎金信问题,这可能属于算法题解部分。引用[4]提到了一刷代码随想录和快慢指针的内容,这可能涉及学习笔记和具体算法技巧。 接下来,我需要将这些信息组织成一个结构清晰的回答。根据用户的要求,回答需要分点说明资源类型,如系统算法题解、数据结构讲解、学习笔记与技巧等,每个部分引用相关的内容,并在末尾添加引用标识。同时,需要确保使用中文,行内公式用$...$,独立公式用$$...$$,但根据用户的问题,可能数学公式的使用不多,但如果有的话需要正确应用。 然后生成相关问题,这些问题应该围绕代码随想录的资源类型、学习路径、具体算法实现等展开,例如如何高效使用该资源,如何结合数据结构学习等。 需要确保回答真实可靠,引用正确。例如,引用[1]中的学习路径和资源链接,引用[3]中的代码示例,引用[4]中的学习笔记内容。 最后,检查格式是否符合要求,没有使用任何markdown,段落之间用空行分隔,引用标识自然添加。确保没有提到任何关于思考过程的内容,保持回答的专业和直接。</think>关于代码随想录的资源与学习内容,以下整理可供参考: ### 一、系统算法题解与数据结构讲解 代码随想录以**循序渐进的学习路径**为核心,从基础数据结构到高阶算法进行分类讲解。例如: - **数据结构学习路径**:数组→链表→哈希表→字符串→栈与队列→树→回溯→贪心→动态规划→图论→高级数据结构[^1] - **经典题目覆盖**:包含高频面试题,例如快速排序的实现与优化、有效字母异位词判断(使用数组替代哈希表)[^3] - **时间复杂度分析**:如暴力法求平方根的时间复杂度为$O(x)$[^2] ### 二、学习笔记与技巧 1. **快慢指针应用**:常用于链表操作与环形检测,通过双指针技巧降低时间复杂度[^4] 2. **代码规范建议**:控制语句(如`while`、`if`)后需添加空格,提升代码可读性[^5] 3. **实战代码示例**:例如赎金信问题中通过数组统计字符频率,实现$O(n)$时间复杂度 ### 三、资源获取方式 - **官方文档**:可访问[代码随想录网站](https://programmercarl.com)查看完整题解 - **GitHub开源项目**:代码与题解仓库位于[leetcode-master](https://github.com/youngyangyang04/leetcode-master)[^1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值