数据结构与算法:前缀和的问题

本文探讨了一种链表处理算法,通过计算链表的前缀和,找出并删除所有和为0的连续子序列。采用HashMap记录前缀和与节点对应关系,实现了高效处理。同时对比了另一种仅使用指针的解决方案,后者在效率上更胜一筹。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

例题:
给你一个链表的头节点 head,请你编写代码,反复删去链表中由 总和 值为 0 的连续节点组成的序列,直到不存在这样的序列为止。

删除完毕后,请你返回最终结果链表的头节点。

数据案例

输入:head = [1,2,-3,3,1]
输出:[3,1]
提示:答案 [1,2,1] 也是正确的。
输入:head = [1,2,3,-3,4]
输出:[1,2,4]
输入:head = [1,2,3,-3,-2]
输出:[1]

之前有做过找最大前缀和的问题,感觉这个连续最大为0的链表题也应该类似。但是对于第一次解决链表前缀和问题,思路想了很久。
思路:
head = [1,2,-3,3,1]
1、对于这组数据来讲,我们可以依次得到他的每一位的前缀和是[1,3,0,3,4],有了这一步,思路就很清晰了,只要找到一样的前缀和,两个数之间的数字都是满足连续和为0的
2、特殊情况的处理:

  • [-1,1]这种刚好从头开始满足条件的数据案例,需要增加哑结点特殊处理
  • [1,2,-3,3,1,-1]得到的子序列和是[1,3,0,3,4,3]已经断过链再次出现断链前内和一样的情况,第二次断链必须是从第一个3开始断链,所以每次断链应该把丢掉的数据及时处理
    3、如何实现?这也是一个难题。最后我选择了用hashMap存放连续和 和 结点地址。大量空间换了时间,但是这样的效率依然不是很高
    //前缀和的问题
    public ListNode removeZeroSumSublists(ListNode head) {
    	ListNode dymmynode = new ListNode(0);
    	dymmynode.next = head;
    	ListNode cur = dymmynode;
    	HashMap<Integer,ListNode> map = new HashMap<>();
    	int count = 0;
    	while(cur != null) {
    		count += cur.val;
    		//不存在的时候
    		if(!map.containsKey(count)) {
    			map.put(count, cur);
    		}else {
    			cur = map.get(count).next;
    			int val = count + cur.val;
    			while(val != count) {
    				map.remove(val);
    				cur = cur.next;
    				val += cur.val;
    				
    			}
    			map.get(count).next = cur.next;
    		}
    		cur = cur.next;
    	}
    	return dymmynode.next;
    }

后来看了一些大佬的题解,这个题可以完全用指针实现,效率极高

class Solution {
    public ListNode removeZeroSumSublists(ListNode head) {
        //生成带头结点的链表
        ListNode dummyHead = new ListNode(0);
        dummyHead.next = head;
        ListNode h = dummyHead;
        
        while(h.next != null){
            ListNode p = h.next;
            ListNode q = p;
            int sum = p.val;    //sum是p至q的总和
            while(q.next != null || sum == 0){   // 加个sum==0的条件,用来处理链表最后n个节点的和为0时的情形如:[1, 2, -2]
                if(sum == 0){   // 先判断sum的值再求和,可以不用对值为0的节点特殊处理
                    h.next = q.next;
                    break;
                }
                q = q.next;
                sum += q.val;
            }
            if(sum != 0) h = h.next;  
        }
        return dummyHead.next;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值