力扣 (LeetCode)算法基础双指针

4 篇文章 0 订阅
3 篇文章 0 订阅

第三天

第六题:删除排序链表中的重复元素 II

82.删除排序链表中的重复元素 II

思路

方法一:
创建新的链表然后找旧链表中不重复的元素加入新链表中然后返回新链表
方法二:
1.创建新的链表并让它与本来的链表相连,两个指针分别指向两个链表。
2.如果head的当前结点的值不等于下一结点的值。那么让指向新链表的指针来到当前结点,这样就链接了前一结点和当前结点。然后head当前结点移至下一结点。
3.如果head当前结点值等于下一结点值。那么就让head一直往后直到当前结点值不等于下一结点value,然后再将当前结点移至下一结点。此时重复节点就过去了,然后让指向新链表的指针来到head开始新一轮的判断。

代码

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        if(head == null || head.next == null){
            return head;
        }
        ListNode phead = new ListNode(0);
        ListNode p = phead;
        while(head != null && head.next != null){
            if(head.val == head.next.val){
                while(head.next != null && head.val == head.next.val){
                    head = head.next;
                }
                head = head.next;
                p.next = head;
            }else{
                p.next = head;
                p = p.next;
                head = head.next;
            }
        }
        return phead.next;
    }
}
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        if(head == null || head.next == null){
            return head;
        }
        ListNode phead = new ListNode(0);
        phead.next = head;
        
        ListNode p = phead;
        while(head != null && head.next != null){
            if(head.val == head.next.val){
                while(head.next != null && head.val == head.next.val){
                    head = head.next;
                }
                //重复元素过滤完进入下一次判断
                head = head.next;
                p.next = head;
            }else{
            	//p = head在出现一次重复元素后相当于p = p.next;但如果链表开始元素不重复则使用p = p.next时第二次进入会出现空指针异常
                p = head;
                head = head.next;
            }
        }
        return phead.next;
    }
}

第七题:三数之和

15.三数之和

思路

1.三数之和为0,可知最小数必然小于等于0,最大数必然大于等于0,要不重复,三数之中只要有两个数不同,要满足和为0,第三数必不同。
2.对原数组进行升序排序,在元素小于等于0的情况下对第一个进行遍历,然后第三个数在元素大于等于0的情况下从数组最后对三个数进行遍历,第二个数下标应该满足大于第一个而小于第三个。
3.可知第二个数和第三个数的确定可以使用双指针。

代码

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums); // 对数组进行升序排序
        ArrayList<List<Integer>> lists = new ArrayList<>();
        for(int i = 0; i < nums.length-2 && nums[i] <= 0; i++){ //对第一个数进行遍历
            if(i > 0 && nums[i] == nums[i-1]){ //去重
                continue;
            }

            int k = nums.length - 1;
            int j = i + 1;
            while(j < k && nums[k] >= 0) { //使用双指针确定第二个数和第三个数下标
                if(nums[i] + nums[j] + nums[k] > 0){ //三数之和大于0,减小第三个数下标
                    k--;
                }else if(nums[i] + nums[j] + nums[k] < 0){ //三数之和小于0,增大第二个数下标
                    j++;
                }else{
                	//找到满足三数之和等于0将其加入列表
                    ArrayList<Integer> list = new ArrayList<>();
                    list.add(nums[i]);
                    list.add(nums[j]);
                    list.add(nums[k]);
                    lists.add(list);

					//对j,k进行去重
                    while(j < k && nums[j] == nums[j+1]) j++;
                    while(j < k && nums[k] >= 0 && nums[k] == nums[k-1]) k--;
                    j++;
                    k--;
                }
            }
        }
        return lists;
    }
}

第四天

第八题:比较含退格的字符串

844.比较含退格的字符串

思路

因已知最大长度,所以可以通过两个字符数组分别计算两个字符串去除退格后的值,并用两个指针记录其长度,如长度不一样则不相等,若长度一样就需要继续比较每一位的值,若出现不相等的,则说明两个字符串不相等。

代码

class Solution {
    public boolean backspaceCompare(String s, String t) {
        char[] S = new char[200];
        char[] T = new char[200];

        int Slength = 0, Tlength = 0;
        char[] schars = s.toCharArray();
        char[] tchars = t.toCharArray();

        for(int i = 0; i < schars.length; i++){
            char c = schars[i];
            if(c != '#'){ //正常字符加入数组中向后移动下标
                S[Slength++] = c;
            }else{
                if(Slength > 0) { //在退格同时保证下标的正确性
                    Slength--;
                }
            }
        }

        for(int i = 0; i < tchars.length; i++){
            char c = tchars[i];
            if(c != '#'){ //正常字符加入数组中向后移动下标
                T[Tlength++] = c;
            }else{
                if(Tlength > 0) { //在退格同时保证下标的正确性
                    Tlength--;
                }
            }
        }

        if(Slength != Tlength){ // 比较长度
            return false;
        }else{
            for(int i = 0; i < Slength; i++){ //比较每一位字符
                if(S[i] != T[i]){
                    return false;
                }
            }
            return true;
        }
    }
}

第九题:区间列表的交集

986.区间列表的交集

思路

1.两个区间只要满足L1 <= R2 和 L2 <= R1,就会存在交集。
2.当存在交集时,交集的开始就是两个区间开始值中的较大一个,交集的结尾肯定是两个区间结束值较小的一个。
3.当使用一个区间的结尾时,说明该区间所有可能和另一个列表中的区间产生的交集全部找到了,此时就可以移动指针到下一个区间。

代码

class Solution {
    public int[][] intervalIntersection(int[][] firstList, int[][] secondList) {
        ArrayList<int[]> ints = new ArrayList<>();
        int flength = 0, slength = 0;
        while(flength < firstList.length && slength < secondList.length){
            if(firstList[flength][1] < secondList[slength][0]){ //firstList在SecondList之前,无交集,移动flength
                flength++;
            }else if(secondList[slength][1] < firstList[flength][0]){ //secondList在firstList之前,无交集,移动slength
                slength++;
            }else{ //存在交集
                int first, end;

				//确定开始
                if (firstList[flength][0] > secondList[slength][0]) {
                    first = firstList[flength][0];
                } else {
                    first = secondList[slength][0];
                }

				//确定结尾
                if (firstList[flength][1] < secondList[slength][1]) {
                    end = firstList[flength][1];
                    flength++;
                } else if (firstList[flength][1] > secondList[slength][1]) {
                    end = secondList[slength][1];
                    slength++;
                } else {
                    end = firstList[flength][1];
                    flength++;
                    slength++;
                }
				
				//加入结果
                ints.add(new int[]{first,end});
            }
        }
		//将结果列表转化为二维数组并返回
        return ints.toArray(new int[0][0]);
    }
}

第十题:盛最多水的容器

11.盛最多水的容器

思路

1.题目意思就是算面积,而面积就是两条高较小的一个乘以下标距离。
2.使用左右指针,其往中间靠拢时距离会减小,为了使面积可能比靠拢之前大,那么最小高度一定要增大,所以就需要移动高度较小的位置的下标,找到比它高的位置,然后再次计算面积并与之前的比较。一直进行这种操作直到两指针重合这样就可以得到最大面积。

代码

class Solution {
    public int maxArea(int[] height) {
        int l = 0, r = height.length-1;
        int sum = 0;
        while(l < r){
            int h1 = height[l];
            int h2 = height[r];
            //判断哪条高较小
            if(h1 < h2){ 
                sum = Math.max(sum,h1 * (r - l)); //更新最大面积
                while(l < r && h1 >= height[l]){  //找比其高的边
                    l++;
                }
            }else{
                sum = Math.max(sum,h2 * (r - l)); //更新最大面积
                while(r > l && h2 >= height[r]){ //找比其高的边
                    r--;
                }
            }
        }
        return sum;
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
力扣是一个在线编程平台,提供了大量的算法题目,可以帮助程序员提高算法能力。回溯算法是一种搜索算法,它通过不断地尝试所有可能的解来求解问题。在回溯算法中,我们首先定义一个解空间,然后从解空间中搜索所有可能的解,直到找到符合要求的解为止。回溯算法通常用于求解组合问题、排列问题、子集问题等。 在 Java 中实现回溯算法,通常需要定义一个递归函数来搜索解空间。在递归函数中,我们首先判断当前状态是否符合要求,如果符合要求,则将当前状态加入到解集中;否则,我们继续搜索下一个状态。在搜索下一个状态时,我们需要对当前状态进行一些修改,然后递归调用自身来搜索下一个状态。当搜索完所有可能的状态后,我们需要回溯到上一个状态,继续搜索其他可能的状态。 以下是回溯算法的一般步骤: 1. 定义解空间:确定问题的解空间,并定义一个数据结构来表示解空间中的每个状态。 2. 确定约束条件:确定哪些状态是合的,并定义一个函数来判断当前状态是否符合要求。 3. 确定搜索策略:确定搜索解空间的顺序,并定义一个函数来生成下一个状态。 4. 搜索解空间:使用递归函数搜索解空间,如果当前状态符合要求,则将其加入到解集中;否则,继续搜索下一个状态。 5. 回溯:当搜索完所有可能的状态后,回溯到上一个状态,继续搜索其他可能的状态。 以下是一个力扣题目的回溯算法 Java 实现示例: ``` class Solution { List<List<Integer>> res = new ArrayList<>(); List<Integer> path = new ArrayList<>(); public List<List<Integer>> subsets(int[] nums) { dfs(nums, 0); return res; } private void dfs(int[] nums, int start) { res.add(new ArrayList<>(path)); for (int i = start; i < nums.length; i++) { path.add(nums[i]); dfs(nums, i + 1); path.remove(path.size() - 1); } } } ``` 该算法用于求解给定数组的所有子集。在递归函数中,我们首先将当前状态加入到解集中,然后从当前位置开始搜索下一个状态。在搜索下一个状态时,我们将当前元素加入到路径中,并递归调用自身来搜索下一个状态。当搜索完所有可能的状态后,我们需要回溯到上一个状态,继续搜索其他可能的状态。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@zhouyu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值