一维数组寻找两个数字之和为N的组合

2023-11-03

问题是这样的,一维数组,包含不重复的数字,求两个数相加之和为N的所有组合。

笛卡尔乘积方式

        public static void Addition2WithCartesian(HashSet<int> hash, int sum)
        {
            Console.WriteLine("通过笛卡尔乘积进行计算2个数字组合(不允许重复)");
            Console.WriteLine("数据源:" + string.Join(" ", hash));
            var query = (from a in hash
                         from b in hash
                         where a + b == sum && a != b
                         select a < b ? $"{a} + {b}" : $"{b} + {a}").Distinct();
            if (!query.Any())
            {
                Console.WriteLine("没有符合相加结果为{0}的数字组合", sum);
            }
            else
            {
                Console.WriteLine("两个数字相加为{0}的组合如下", sum);
                foreach (var tmp in query)
                {
                    Console.WriteLine(tmp);
                }
            }
        }

这种方式虽然能出结果,但明显不是对方期望的结果,要求其它方式

遍历HashSet方式

        public static void Addition2WithNormal(HashSet<int> hash, int sum)
        {
            Console.WriteLine("HashSet计算2个数字组合");
            Console.WriteLine("数据源:" + string.Join(" ", hash));
            while (hash.Count > 1)
            {
                var number = hash.First();
                hash.Remove(number);
                var needNumber = sum - number;
                if (hash.Contains(needNumber))
                {
                    hash.Remove(needNumber);
                    Console.WriteLine($"{number} + {needNumber} = {sum}");
                }
            }//O(n)
        }

通过空间换时间,这里直接用HashSet<T>作为数组源,当集合剩余数字只有一个时,就可以结束循环,所以此时只需循环N-1次,时间复杂度是O(n)

出题方有些不开心,追问那现在数组变了,可以存在重复的数字,每个数字只能用一次,这时候如何获取所有的组合?

传统的两层循环方式

        public static void Addition2Slowest(List<int> source, int sum)
        {
            Console.WriteLine("两层循环计算2个数字组合(允许存在重复数字)");
            Console.WriteLine("数据源:" + string.Join(" ", source));
            for (var i = 0; i < source.Count - 1; i++)
            {
                for (var j = 1; j < source.Count; j++)
                {
                    if (source[i] + source[j] == sum)
                    {
                        Console.WriteLine($"{source[i]} + {source[j]} = {sum}");
                        source.RemoveAt(j);
                        source.RemoveAt(i);
                        i--;
                        break;
                    }
                }
            }//O(n^2) 最小O(n)
        }

好吧,因为要移除已匹配的数字,所以不能用Array,好家伙,占了空间不说,时间复杂度也没少为O(n^2)
PS:用Array其实也可以,RemoveAt调整为设置数字值为null,循环时多一次null判断

遍历Dictionary方式

        public static void Addition2RepeatWithNormal(IEnumerable<int> source, int sum)
        {
            //C#内置集合类的时间复杂度 https://www.cnblogs.com/wccfsdn/p/11945454.html
            Console.WriteLine("Dictionary计算2个数字组合(允许存在重复数字)");
            Console.WriteLine("数据源:" + string.Join(" ", source));
            //GroupBy O(n)   ToDictionary O(n) 也可以自行for循环 O(n)
            var dic = source.GroupBy(_ => _).ToDictionary(k => k.Key, v => v.Count()); 
            while (dic.Count > 0)//必须是0,避免出现sum是偶数,数据源中存在重复的sum/2数字
            {
                var number = dic.First().Key;//遍历是O(n),First是O(1)
                CheckKey(number);
                var needNumber = sum - number;
                if (dic.ContainsKey(needNumber))
                {
                    CheckKey(needNumber);
                    Console.WriteLine($"{number} + {needNumber} = {sum}");
                }
            }//O(n)

            void CheckKey(int key)
            {
                dic[key]--; //O(1)
                if (dic[key] == 0) //O(1)
                {
                    dic.Remove(key); //O(1)
                }
            }
        }

本质其实与HashSet<T>方式并没有太大差异,只是由直接HashSet<T>.Remove,变成了需要先判断下是否还有可用数字,只有数字数量为0时才执行Remove,当然时间复杂度也还是O(n)

排序后双指针方式

        public static void Addition2RepeatWithDoublePointer(IEnumerable<int> source, int sum)
        {
            //排序的时间复杂度影响整个组合的时间复杂度
            var tmpList = source.OrderBy(_ => _).ToList();
            Console.WriteLine("双指针方式计算2个数字组合(允许存在重复数字)");
            Console.WriteLine("排序后的数据源:" + string.Join(" ", tmpList));
            int i = 0, j = tmpList.Count - 1;
            while (i < j)
            {
                while (j > i)
                {
                    var tmpSum = tmpList[i] + tmpList[j];
                    if (tmpSum <= sum)
                    {
                        if (tmpSum == sum)
                        {
                            Console.WriteLine($"{tmpList[i]} + {tmpList[j]} = {sum}");
                            j--;
                        }
                        //两数之和小于sum时,应当停止循环,且不更改指针
                        break;
                    }
                    j--;
                }
                i++;
            }
        }

这种方式虽然看起来有两层循环,但其实每个数字都只能被循环到一次,所以其时间复杂度还是为O(n)

测试上面的所有方式

            var hash = Enumerable.Range(-5, 15).ToHashSet();
            var repeatSource = Enumerable.Range(-7, 12).ToList();
            repeatSource.AddRange(hash);//构建重复数据
            var sum = 6;

            Addition2WithCartesian(hash, sum);
            Console.WriteLine();

            Addition2Slowest(repeatSource.ToList(), sum);
            Console.WriteLine();

            Addition2WithNormal(hash, sum);
            Console.WriteLine();

            Addition2RepeatWithNormal(repeatSource, sum);
            Console.WriteLine();

            Addition2RepeatWithDoublePointer(repeatSource, sum);

执行结果如下
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

一维数组寻找两个数字之和为N的组合 的相关文章

随机推荐

  • 几种字符串补“0”(或其它字符)的方式

    几种字符串补 0 或其它字符 的方式 好记性不如烂笔头 先记下 呵呵 方式一 这个最多程序员用的 也是最普通的方式 int a 656 string b a if b length lt 6 for int i 0 i lt 6 b len
  • 参数在信号-槽参数用值传递还是引用传递

    结论 以下表格总结了我们的结果 例如第一行 如果程序传递信号的参数为引用到槽 那么在直接连接则不发生复制 在队列连接则发生一次复制 Signal Slot Direct Queued const Copy const Copy 0 1 co
  • Matlab找出矩阵每一行的最大值及其位置

    dis max arr 2 dis array zeros M N for i 1 size dis hang max dis i 1 c find edtImage i hang max dis array i c 1 end figur
  • 移植NTP时间同步工具到arm linux平台创建定时任务

    移植NTP时间同步工具到arm linux平台创建定时任务 下载源码 解压并编译 一个脚本进行编译 上传文件至开发板 运行 创建开机启动项 注意在windows上编写的文件可能需要执行以下命令 ntp服务器 下载源码 wget c http
  • (ubuntu)linux和mac安装Miracl密码库

    只要你按照以下步骤操作 可以得到Miracl密码库的静态编译文件 a 步骤一 官网仓库 注意 是下载ZIP 而不是直接clone下来 不然的话是绝对不行的 步骤二 unzip j aa L MIRACL master zip 执行命令 终端
  • spring中的动态代理

    两种代理原理 jdk动态代理是利用反射机制生成一个实现代理接口的匿名类 在调用具体方法前调用InvokeHandler来处理 cglib动态代理是利用asm开源包 对代理对象类的class文件加载进来 通过修改其字节码生成子类来处理 spr
  • [Android常见问题] 自定义授权界面

    自定义授权界面 http bbs mob com thread 278 1 1 html 出处 http bbs mob com 本帖最后由 wolf 于 2016 5 6 10 30 编辑 自定义授权界面 1 准备工作 参考文档 在你的项
  • Couldn‘t find meta-data for provider with authority com.wust.camerademo

    报错信息 Couldn t find meta data for provider with authority com wust camerademo 报错原因 AndroidManifest xml 清单文件中未注册 provider
  • ae渲染出现错误是什么问题_After Effects错误:写入文件.....时发生渲染错误.输出模块失败.文件可能已损坏。(-1610153464)...

    我来回答一下 你在电脑里安装了其他下载的aex文件格式的插件 你只要把你这些插件删除掉 问题就可以解决 安装插件不正确 或者有相同的插件也出现提示框 其实 这个提示不重要 你正常开启AE以后 正常使用软件 只是 安装错误的插件 使用起来没有
  • 正负样本不平衡处理方法总结

    1 Bootstrapping hard negative mining 最原始的一种方法 主要使用在传统的机器学习方法中 比如 训练随机森林 对于每一个树就是采样booststraping方法采样 也算是随机森林的其中一个随机性表现 再比
  • java 获取当前时间所在月份的每周日期区间

    获取当前时间所在月份的每周日期区间 每周的起始日是周一 结束日期是周日 例子 假设当前时间是2020 03 04 那么这个月跨度有6周 第一周 2020 03 01 2020 03 01 第二周 2020 03 02 2020 03 08
  • 个人用户如何搭建一个全面的WEB服务器(中)

    第四 建立Win Media在线影视 按照第一步中图三 图四和图五的走法 只不过在图五中选择 流式媒体服务器 点击确定 这样系统将会自动在你的WEB服务器下创建一个Win Media流式媒体服务器站点 接下来就是如何管理这个服务器以及制作流
  • Pytorch+LSTM 的 英译中

    usr bin env Python3 coding utf 8 version v1 0 Author Meng Li contact 925762221 qq com FILE torch seq2seq py Time 2022 6
  • 【记录】看门狗定时器基础

    原文 概要 我们平时使用的电脑 由于某种原因导致动作异常 反复执行指定外的操作 或者没有任何反应 这种情况被认定为程序失控 out of control 或者程序中止了 对于用户而言 可以知道程序出现了异常 需要采取一定的措施 对于嵌入式系
  • 华为OD机试真题-任务调度【2023.Q1】

    题目内容 现有一个CPU和一些任务需要处理 已提前获知每个任务的任务ID 优先级 所需执行时间和到达时间 CPU同时只能运行一个任务 请编写一个任务调度程序 采用 可抢占优先权调度 调度算法进行任务调度 规则如下 1 如果一个任务到来时 C
  • Spring源码剖析之IOC容器创建流程

    ApplicationContextConfiguration为核心配置类 ApplicationContext applicationContext new AnnotationConfigApplicationContext Appli
  • Android手机RTMP播放工具(APK,支持秒开)

    Android手机RTMP播放工具是一款可以在安卓手机播放rtmp流的工具 基于FFmpeg openCV开发 下载地址 Android手机RTMP播放工具 APK 支持秒开 C 文档类资源 CSDN下载
  • 【后端】SSM框架体系(一)

    SSM框架 Spring 一 Spring相关概念 1 初识Spring 1 1 Spring家族 官网 https spring io 从官网我们可以大概了解到 Spring能做什么 用以开发web 微服务以及分布式系统等 光这三块就已经
  • gpexpand分析

    欢迎大家前往腾讯云 社区 获取更多腾讯海量技术实践干货哦 本文由maxluo发表于云 社区专栏 一 gp扩容步骤 1 1 初始化机器 目标 新增加的机器需要初始化和已有机器环境一样 具体包括不限于以下内容 创建用户名 设置环境变量 创建数据
  • 一维数组寻找两个数字之和为N的组合

    问题是这样的 一维数组 包含不重复的数字 求两个数相加之和为N的所有组合 笛卡尔乘积方式 public static void Addition2WithCartesian HashSet