k-sum问题及变种题算法总结(持续更新中)


1. 青铜: leetcode-1. 两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

虽然本题是青铜级,但是如果你写两层for循环时间复杂度为 O ( n 2 ) O(n^2) O(n2)的算法,也太说不过去了吧,估计只能算个废铁级。为了进入青铜级入门水平,我们可以用一个字典来存元素和下标,这样查找时间就为 O ( 1 ) O(1) O(1)

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        num_index={}
        for i in range(0,len(nums)):
            num_index[nums[i]]=i
        for i in range(0,len(nums)):
            temp=target-nums[i]
            if temp in num_index.keys() and i!=num_index[temp]:
                return [i,num_index[temp]]
        return []

2. 白银:2-sum问题变种之找出所有不重复的结果

给定一个整数数组 nums(里面没有重复元素) 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的所有的两个整数组合情况,并返回这样的整数组合对。

可以在上一节的答案基础上,循环遍历时把所有结果append到一个数组中。但是要注意判断元素是不是已经在之前出现过

class Solution:
    def twoSum(self, nums, target: int):
        results=[]
        num_index={}
        set_second_ele=set()
        for i in range(0,len(nums)):
            num_index[nums[i]]=i
        for i in range(0,len(nums)):
            temp=target-nums[i]
            if temp in num_index.keys() and i!=num_index[temp] and not temp in set_second_ele:
                results.append([nums[i],temp])
                set_second_ele.add(nums[i])
        return results

如果nums里面有重复元素咋办?只需要做一点小修改就行

class Solution:
    def twoSum(self, nums, target: int):
        results=[]
        num_index={}
        set_second_ele=set()
        for i in range(0,len(nums)):
            num_index[nums[i]]=i
        for i in range(0,len(nums)):
            temp=target-nums[i]
            if temp in num_index.keys() and i!=num_index[temp] and not nums[i] in set_second_ele and not temp in set_second_ele:
                results.append([nums[i],temp])
                set_second_ele.add(nums[i])
        return results

3. 黄金:leetcode-15. 三数之和

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。
可以转化为2-sum问题,注意要去重。

class Solution:
    def twoSum(self, nums, target: int, index_a: int,set_a,set_index_a):
        results=[]
        num_index={}
        set_second_ele=set()
#        set_first_ele=set()
        for i in range(0,len(nums)):
            num_index[nums[i]]=i
        for i in range(index_a+1,len(nums)):
            if i==index_a:
                continue
            temp=target-nums[i]
            if temp in num_index.keys() and i<num_index[temp] and not temp in set_second_ele and nums[i] not in set_second_ele and num_index[temp]!=index_a and not i in set_index_a and not num_index[temp] in set_index_a:
                results.append([nums[i],temp])
                set_second_ele.add(nums[i])
#                set_first_ele.add(nums[i])
        return results
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        results=[]
        num_index={}
        nums.sort()
        for i in range(0,len(nums)):
            num_index[nums[i]]=i
        set_a=set()
        set_index_a=set()
        for index_a,a in enumerate(nums):
            if a in set_a:
                continue
            two_sum_result=self.twoSum(nums,0-a,index_a,set_a,set_index_a)
            set_a.add(a)
            set_index_a.add(index_a)
            for result in two_sum_result:
                results.append([a]+result)
        return results

还有一种更适合推广到k-sum的情况的算法,就先对数组排序,然后从低到高选择不重复的元素进行组合,检查是否满足要求:

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        results=[]
        nums.sort()
        third_index_start=len(nums)-1
        for first_index in range(0,len(nums)):
            if first_index==0 or nums[first_index]!=nums[first_index-1]:
                target1=-nums[first_index]
                third_index=third_index_start
                for second_index in range(first_index+1,len(nums)):
                    if second_index==first_index+1 or nums[second_index]!=nums[second_index-1]:
                        target2=target1-nums[second_index]      
                        if target2>nums[third_index_start]:
                            continue
                        while third_index>second_index and target2<nums[third_index]:
                            third_index-=1
                        if third_index==second_index:
                            break
                        if target2==nums[third_index]:
                            results.append([nums[first_index],nums[second_index],nums[third_index]])
        return results

4. 铂金:k数之和

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在k个元素,并且这k个元素之和等于target ?请你找出所有这样的不重复的k元组。

注意:答案中不可以包含重复的k元组。

class Solution:
    def recursive(self,start_index,current_cycle,target):
        if current_cycle==self.total_cycle-1:
            third_index=self.last_index#放到这里可减少一些操作
            for second_index in range(start_index+1,self.n):
                if second_index==start_index+1 or self.nums[second_index]!=self.nums[second_index-1]:
                    self.temp_result[current_cycle]=self.nums[second_index]
                    target2=target-self.nums[second_index]     
                    if target2>self.nums[self.last_index]:
                        continue#剪枝
                    while third_index>second_index and target2<self.nums[third_index]:
                        third_index-=1
                    if third_index==second_index:
                        break#剪枝
                    if target2==self.nums[third_index]:                        self.temp_result[self.total_cycle]=self.nums[third_index]
                        self.results.append([ele for ele in self.temp_result])
            return
        else:
            for first_index in range(start_index+1,self.n):
                if first_index==start_index+1 or self.nums[first_index]!=self.nums[first_index-1]:
                    self.temp_result[current_cycle]=self.nums[first_index]      
                    target1=target-self.nums[first_index]                    self.recursive(first_index,current_cycle+1,target1)

    def kSum(self, nums: List[int], target: int, k: int) -> List[List[int]]:
        nums.sort()
        self.nums=nums
        self.n=len(nums)
        self.last_index=self.n-1
        self.results=[]
        self.total_cycle=k-1
        self.temp_result=[0]*(self.total_cycle+1)
        start_index=-1
        current_cycle=0
        #print(self.nums)
        self.recursive(start_index,current_cycle,target)
        return self.results

5. 钻石:最接近的k数之和

给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出k个整数,使它们的和与 target 最接近。

返回这k个数的和。

假定每组输入只存在恰好一个解。

本题的实际例子就是leetcode 16. 最接近的三数之和

解法是基于第4章之上的,区别在于需要动态更新k数之和与target的差(注意要取绝对值),以及对应地更新k数之和。最终选择最接近k数之和作为result

class Solution:
    def recursive(self,start_index,current_cycle,target):
        if current_cycle==self.total_cycle-1:
            for second_index in range(start_index+1,self.n):
                if second_index==start_index+1 or self.nums[second_index]!=self.nums[second_index-1]:
                    third_index=self.last_index#注意不能放到前面了,必须放在这里,因为没有剪枝操作,需要完成second_index的循环。每轮迭代需要将third_index重置
                    target2=target-self.nums[second_index]
                    while third_index>second_index:
                        cur_dev=target2-self.nums[third_index]
                        if abs(cur_dev)<self.deviation:
                            self.deviation=abs(cur_dev)
                            self.result=self.target-cur_dev
                        third_index-=1
            return
        else:
            for first_index in range(start_index+1,self.n):
                if first_index==start_index+1 or self.nums[first_index]!=self.nums[first_index-1]:
                    target1=target-self.nums[first_index]
                    self.recursive(first_index,current_cycle+1,target1)
    def threeSumClosest(self, nums: List[int], target: int) -> int:
        self.deviation=99999999
        self.target=target
        nums.sort()
        self.nums=nums
        print(nums)
        self.n=len(nums)
        self.last_index=self.n-1
        self.result=0
        self.total_cycle=3-1
        start_index=-1
        current_cycle=0
        self.recursive(start_index,current_cycle,self.target)
        return self.result
  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
PSO算法、蚁群算法和遗传算法都是优化算法,可以用于解决函数最值问题。下面是各个算法的Matlab代码示例: PSO算法: ```matlab function [x,fval] = PSO(fitnessfun,nvars,lb,ub,options) % fitnessfun: 适应度函数句柄 % nvars: 变量个数 % lb, ub: 变量的上下界 % options: PSO算法参数 % 初始化 swarmsize = options.SwarmSize; c1 = options.CognitiveAttraction; c2 = options.SocialAttraction; w = options.InertiaWeight; maxiter = options.MaxIterations; x = repmat(lb,swarmsize,1) + repmat((ub-lb),swarmsize,1).*rand(swarmsize,nvars); v = zeros(swarmsize,nvars); pbest = x; pbestval = feval(fitnessfun,x); [gbestval,idx] = min(pbestval); gbest = pbest(idx,:); % 迭代 for i = 1:maxiter % 更新速度和位置 v = w*v + c1*rand(swarmsize,nvars).*(pbest-x) + c2*rand(swarmsize,nvars).*(repmat(gbest,swarmsize,1)-x); x = x + v; % 边界处理 x(x<lb) = lb(x<lb); x(x>ub) = ub(x>ub); % 更新个体最优值和群体最优值 fx = feval(fitnessfun,x); change = fx<pbestval; pbestval(change) = fx(change); pbest(change,:) = x(change,:); [minval,idx] = min(pbestval); if minval<gbestval gbestval = minval; gbest = pbest(idx,:); end % 更新惯性权重 w = options.InertiaWeightFcn(w,i); end % 返回结果 x = gbest; fval = gbestval; ``` 蚁群算法: ```matlab function [x,fval] = AntColony(fitnessfun,nvars,lb,ub,options) % fitnessfun: 适应度函数句柄 % nvars: 变量个数 % lb, ub: 变量的上下界 % options: 蚁群算法参数 % 初始化 antsize = options.AntSize; alpha = options.Alpha; beta = options.Beta; rho = options.Rho; q0 = options.Q0; maxiter = options.MaxIterations; pheromone = ones(nvars,nvars)/(nvars*nvars); x = repmat(lb,antsize,nvars) + repmat((ub-lb),antsize,1).*rand(antsize,nvars); bestx = []; bestfval = Inf; % 迭代 for i = 1:maxiter % 移动蚂蚁 for j = 1:antsize curx = x(j,:); visited = zeros(1,nvars); visited(curx) = 1; for k = 2:nvars prob = zeros(1,nvars); for m = 1:nvars if ~visited(m) prob(m) = pheromone(curx,m)^alpha * (1/abs(m-curx))^beta; end end if rand < q0 [~,idx] = max(prob); else prob = prob/sum(prob); cumprob = cumsum(prob); [~,idx] = find(cumprob>rand,1); end curx(k) = idx; visited(idx) = 1; end % 更新最优解 fval = feval(fitnessfun,curx); if fval < bestfval bestx = curx; bestfval = fval; end end % 更新信息素 delta_pheromone = zeros(nvars,nvars); for j = 1:antsize for k = 1:(nvars-1) delta_pheromone(x(j,k),x(j,k+1)) = delta_pheromone(x(j,k),x(j,k+1)) + 1/feval(fitnessfun,x(j,:)); end end pheromone = (1-rho)*pheromone + delta_pheromone; end % 返回结果 x = bestx; fval = bestfval; ``` 遗传算法: ```matlab function [x,fval] = GeneticAlgorithm(fitnessfun,nvars,lb,ub,options) % fitnessfun: 适应度函数句柄 % nvars: 变量个数 % lb, ub: 变量的上下界 % options: 遗传算法参数 % 初始化 popsize = options.PopulationSize; mutationrate = options.MutationRate; crossoverfraction = options.CrossoverFraction; maxgenerations = options.MaxGenerations; pop = repmat(lb,popsize,1) + repmat((ub-lb),popsize,1).*rand(popsize,nvars); fitness = feval(fitnessfun,pop); [bestfval,idx] = min(fitness); bestx = pop(idx,:); % 迭代 for i = 1:maxgenerations % 选择 [parents,parentsfitness] = roulette(pop,fitness); % 交叉 n = round(crossoverfraction*popsize/2)*2; children = zeros(n,nvars); for j = 1:n/2 p1 = parents(randi(length(parents)),:); p2 = parents(randi(length(parents)),:); [c1,c2] = crossover(p1,p2); children(2*j-1,:) = c1; children(2*j,:) = c2; end % 变异 n = round(mutationrate*popsize); idx = randperm(popsize,n); pop(idx,:) = repmat(lb,n,1) + repmat((ub-lb),n,1).*rand(n,nvars); % 合并 pop = [pop;children]; fitness = [fitness;feval(fitnessfun,children)]; % 精英保留 [fitness,idx] = sort(fitness); pop = pop(idx,:); pop = pop(1:popsize,:); fitness = fitness(1:popsize); % 更新最优解 if fitness(1) < bestfval bestfval = fitness(1); bestx = pop(1,:); end end % 返回结果 x = bestx; fval = bestfval; ``` 需要注意的是,这里的适应度函数和算法参数需要根据实际问题进行设置。这些算法也有很多的变种和改进,可以根据具体情况进行选择和修改。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值