LeetCode(15) 3Sum

本文介绍LeetCode第14题的解决方案,探讨如何高效找出数组中所有和为0的三元组,并通过优化算法减少运行时间。文章对比了不同实现方法的效率,包括使用排序、双重循环和计数器等技术。

https://sodaoo.github.io/2017/11/21/LeetCode-14/
https://sodaoo.github.io

来我的网站查看更多 LeetCode 题解


Description :

An array S of n integers .are there elements a, b, c in S such that a+b+c=0 ?
Find all unique triplets in the array which gives the sum of zero.
Note: The solution set must not contain duplicate triplets.
For example, given array S = [-1, 0, 1, 2, -1, -4],
A solution set is:
[ [-1, 0, 1], [-1, -1, 2] ]


给你一个 int 类型的Array , 将所有相加等于0 的三个数找出来, 返回一个三元组的表 .
这个表一定不能重复 ,比如 : [-1,-1,2 ] 和 [-1,2,-1] 被认为是重复的 .
A solution set is:
[ [-1, 0, 1], [-1, -1, 2] ]


常规思路 :
– 将这个数组排序, 比如排序之后是 nums=(-99,-56,-34,-1,0,22,33,44,77)
– 写双重的 for 循环 ,判断 x = -(nums[i] , nums[j]) 是否在 nums[] 内
– 如果 x 在 nums[] 之内 : 说明找到了这样三个数 ,如果不在 就继续循环 .

for i in range(len(nums)):
   for j in range(i+1,len(nums)):
      if (0-nums[i]-nums[j]) in nums:
         a = list();
         a.append(0-nums[i]-nums[j]);a.append(nums[i]);a.append(nums[j])
         res.append(a)
# 有可能有重复的三元组, 我们对每一个三元组排序,再去重就可以了 .
# [-1,-1,2 ] 和 [-1,2,-1] 被认为是重复的.但是这两个被认为是不相等的 .
# 所以我们排序, [-1,-1,2 ] 和 [-1,-1,2 ] 是相等的 .利用这一点去重 .
# 去重代码 :
    for i in res:
        i.sort()     # 对三元组排序
    ress = list()    
    for i in res:
        if i not in ress:
            ress.append(i)

这个代码写出来 , 用了三千个数据一跑 ,光荣的达到了两分钟之久, 我们
import time ;
t1 = time.time() ; t2 = time.time()
print(“t1 到 t2 耗时共计”,t2-t1,”秒.”) 发现 ,
查找的代码耗时 133s , 去重排了 3s 贼恐怖 .

科学计算
Python拥有一些内置的数据结构 ,比如str, int, list, tuple, dict等, collections模块在这些内置数据结构的基础上,提供了几个额外的数据结构:
– namedtuple(): 生成可以使用名字来访问元素内容的tuple子类
– deque: 双端队列,可以快速的从另外一侧追加和推出对象
– Counter: 计数器,主要用来计数
– OrderedDict: 有序字典
– defaultdict: 带有默认值的字典

忽然发现我们常用的 list , dict 处理大批数据的能力真的很慢 ,
(也许不是慢 ,是打开方式不对…)

有一个有100万元素的列表Lis ,欲将每个元素和其出现次数成对放入一个字典中 .常规做法:

dic = {}
for i in Lis:
    dic[i] = Lis.count(i)

但发现非常耗时,一秒钟只能遍历300多个元素。 这就非常蛋疼了 .此时我们可以引入一个collections库 ,
这个库里面有一个 计数器 Counter , 不知道采用了什么样的结构, 总之非常快
不到一秒钟就完成了上面的任务 ,代码 :

import collections
cou = collections.Counter(Lis)
print(cou)        #不到一秒钟就完成了 


我们再来看一下计数器的特点 :

>>> a = [2,2,2,3,3,4]
>>> cou = collections.Counter(a)
>>> cou
Counter({2: 3, 3: 2, 4: 1})     # 元素后面是出现的次数
>>> 4 in cou
True
>>> 1 in cou
False

>>> cou[3]
2
>>> cou[4]
1
>>> cou[2]
3
# cou[n] 是表示 n 这个元素出现的次数, 如示 3 这个元素出现了3 次, 2 这个元素出现了 3 次.

依据这一特点, 我们对我们耗时 3 分钟的代码做一下改进 :
改进之后, 查找的时间降低到了 4 s 去重的时间降低到了 0.003 s

import collections
class Solution:
    def threeSum(self, nums):
        counter = collections.Counter(nums)
        del nums ; nums = counter # nums现在是一个计数器 .
        res = list()
        for i in range(len(nums)):
            for j in range(i+1,len(nums)):
# 下面都是一样的了........


虽然速度快了非常多, 但是还是超时 ,下面我们看一个 AC 的 702 ms 的代码:

from collections import Counter
class Solution:
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        counter = collections.Counter(nums)
        # 如果 0 出现的次数 > 3 ,就加入一个 [0,0,0] 的三元组
        ans = [] if counter[0] < 3 else [[0, 0, 0]]

        # 负数由大到小, 如 (-2 到 -77777)
        ngs = sorted([x for x in counter if x<0], reverse=True)
        # 正数由小到大, 如 (2 到 88888 )
        n_ngs = sorted([x for x in counter if x>=0])

        # 正负排序之后 , 更利于查找
        # 双重循环
        for n_ng in n_ngs:
            for ng in ngs:
                need = -(ng + n_ng)    # <-need是第三个数
                if need in counter:
                    # 根据大小决定在元组的顺序, 不用去重了 .
                    if (need == ng or need == n_ng) and counter[need] > 1:
                        ans.append([ng, need, n_ng])
                    elif need < ng: ans.append([need, ng, n_ng])
                    elif n_ng < need: ans.append([ng, n_ng, need])
        return ans
  # (time :1522 ms ,beat 51.82%)


C++ 解法 :

vector<vector<int> > threeSum(vector<int> &num) {
  vector<vector<int> > res;
  std::sort(num.begin(), num.end());
  for (int i = 0; i < num.size(); i++) {
    int target = -num[i];
    int front = i + 1;
    int back = num.size() - 1;
    while (front < back) {
      int sum = num[front] + num[back];
      // Finding answer which start from number num[i]
      if (sum < target)
        front++;
      else if (sum > target)
        back--;
      else {  //find sum == target that is -num[i] .
        vector<int> triplet(3, 0);
        triplet[0] = num[i];
        triplet[1] = num[front];
        triplet[2] = num[back];
        res.push_back(triplet);

        // Processing duplicates of Number 2
        // Rolling the front pointer to the next different number forwards
        while (front < back && num[front] == triplet[1]) front++;
        // Processing duplicates of Number 3
        // Rolling the back pointer to the next different number backwards
        while (front < back && num[back] == triplet[2]) back--;
      }
    }
    // Processing duplicates of Number 1
    while (i + 1 < num.size() && num[i + 1] == num[i])
      i++;
  }
  return res;
}
  //  (time :105ms ,beat 80.2% )
带开环升压转换器和逆变器的太阳能光伏系统 太阳能光伏系统驱动开环升压转换器和SPWM逆变器提供波形稳定、设计简单的交流电的模型 Simulink模型展示了一个完整的基于太阳能光伏的直流到交流电力转换系统,该系统由简单、透明、易于理解的模块构建而成。该系统从配置为提供真实直流输出电压的光伏阵列开始,然后由开环DC-DC升压转换器进行处理。升压转换器将光伏电压提高到适合为单相全桥逆变器供电的稳定直流链路电平。 逆变器使用正弦PWM(SPWM)开关来产生干净的交流输出波形,使该模型成为研究直流-交流转换基本操作的理想选择。该设计避免了闭环和MPPT的复杂性,使用户能够专注于光伏接口、升压转换和逆变器开关的核心概念。 此模型包含的主要功能: •太阳能光伏阵列在标准条件下产生~200V电压 •具有固定占空比操作的开环升压转换器 •直流链路电容器,用于平滑和稳定转换器输出 •单相全桥SPWM逆变器 •交流负载,用于观察实际输出行为 •显示光伏电压、升压输出、直流链路电压、逆变器交流波形和负载电流的组织良好的范围 •完全可编辑的结构,适合分析、实验和扩展 该模型旨在为太阳能直流-交流转换提供一个干净高效的仿真框架。布局简单明了,允许用户快速了解信号流,检查各个阶段,并根据需要修改参数。 系统架构有意保持模块化,因此可以轻松扩展,例如通过添加MPPT、动态负载行为、闭环升压控制或并网逆变器概念。该模型为进一步开发或整合到更大的可再生能源模拟中奠定了坚实的基础。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值