首先来思考一个问题,现在有一个数组A = [1,2,3,4,5,4,3,2,1,2,3,4,5,4,3,2,1],数组内有一些元素有重复数据,现在要求你给出对于数组中的每一个元素,在右(左)侧有多少元素和它相等(不包括本身),有多少元素大于它,有多少元素的两倍小于(大于)它,3倍,平方.... 甚至更加一般的,有多少元素 (A[i],A[j])(i<j<A.length) 满足Fun(A[i],A[j])?

最笨的一种方法:

int res = 0;
for(int i=0;i<A.length;i++){for(int j=i+1;j<A.length;j++){if(Fun(A[i],A[j]) == true) res += 1;}
}
return res;

这种方法的时间复杂度是O(n*n/2),显然是难以让人满意的。

在算法领域,要想降低算法复杂度,就要提高空间复杂度,即所谓的拿空间换时间。如果我们想用空间换时间该怎么换呢?

我们把数组从后向前遍历,每遍历一个元素就把它放到一个仓库里,然后每次求这个元素在仓库里有几个符合条件的值时,直接去仓库里找。只要在仓库里查找和添加、删除足够快(在O(C)时间内完成),我们的时间复杂度就会降低到O(C*n),这显然是可以接受的。

那么有没有这么一种仓库(数据结构),可以实现常数时间内查找、添加、删除元素呢?答案是有的,就是字典树。

我们知道,每一个int都有32位组成。而每一位只有可能是0或者1.这样,只要创建一个深度为32的二叉树就可以描述所有int了。对于每个int的插入、删除、查找的时间都是是32,可见字典树是可以满足我们的需求的。

将问题发散开去,字典树适用于创建那种集合整体可以被[有限个维度]描述的"仓库",而且对单个元素的增加、修改、查找的时间复杂度就是[维度]。


例如英文文章的词频统计,记录每个单词出现的频率,完全可以用字典树来实现。描述所有单词的一个维度就是单词的内容,即一串英文字符,他们的长度虽然可能各不相同,但是总体上是有限的,即[1,100]。而英文字符也是有限集合,通过ASIIC码可以区分他们。

要想用好字典树,一个很关键的因素就是能不能找到一组有限维度来描述整个集合。

然后贴上一段代码:

/******* 利用字典树保存数组中所有的数*2的值,之后从右向左遍历数组,首先将这个数*2的值从树中删除,然后查找树中比* 这个数小的元素的个数。* 最坏时间复杂度: O(96 * n)* 插入、删除、查找还利用了尾递归来加快速度**/
public class Solution {public int reversePairs(int[] nums) {int res = 0,lenn = nums.length;//,halfMax = (Integer.MAX_VALUE)/2+10;if(lenn<2) return 0;Node head = new Node();long temp = nums[lenn-1];//if(nums[lenn-1] < halfMax) addNum(temp *2,head,63);for(int i=lenn-2;i>-1;i--){temp = nums[i];res += getRes(temp,head,63,0);addNum(temp *2,head,63);}return res;}private void delNum(long tar,Node he,int bit){// 删除树中这个元素,并且更新相关节点的值if(bit<0)return ;if((tar & (((long)1)<<bit)) == 0){if(he.zero.num > 0)he.zero.num -= 1;//else return ;he = he.zero;}else{if(he.one.num > 0)he.one.num -= 1;//else return ;he = he.one;}delNum(tar,he,bit-1);}private void addNum(long tar,Node he,int bit){// 向树中增加这个元素,并且更新相关节点的值if(bit<0)return;if((tar & (((long)1)<<bit)) == 0){if(he.zero == null) he.zero = new Node();else he.zero.num += 1;he = he.zero;}else{if(he.one == null) he.one = new Node();else he.one.num += 1;he = he.one;}addNum(tar,he,bit-1);}private int getRes(long tar,Node he,int bit,int res){// 符号位特殊判断if(tar>=0){if(he.one != null)res += he.one.num;he = he.zero;}else{he = he.one;}return getSmallerNum(tar,he,bit-1,res);}private int getSmallerNum(long tar,Node he,int bit,int res){// 获取比tar小的所有数的个数,据说是尾递归if(bit<0 || he == null) return res;if((tar & (((long)1)<<bit)) == 0){he = he.zero;}else{if(he.zero != null)res += he.zero.num;he = he.one;}return getSmallerNum(tar,he,bit-1,res);}private static class Node{public int num;public Node zero,one;public Node(){num = 1;zero = null;one = null;}}
}

转载于:https://www.cnblogs.com/GUK0/p/6513998.html

对于整数数组类的算法的终极解决方案相关推荐

  1. 火山视窗整数数组类增删查改操作

    本源码转载自利快云https://www.lkuaiy.com/ 火山视窗整数数组类增删查改操作     整数数组类可对整数数据进行数组操作,本类可以非常方便的实现对整数数组的增删查改.   一.添加 ...

  2. .net 遍历数组找重复值写入一个新数组_面试 | 数组类算法精析

    点击上方蓝字设为星标 每周一.三.五上午 8:30 准时推送 下面开始今天的学习- 面试中的算法问题,有很多并不需要复杂的数据结构支撑.就是用数组,就能考察出很多东西了.其实,经典的排序问题,二分搜索 ...

  3. 本题要求实现一个用选择法对整数数组进行简单排序的函数。_通俗易懂讲 Python 算法:快速排序...

    原文:https://stackabuse.com/quicksort-in-python/ 作者:Marcus Sanatan 译者:老齐 欢迎在 bilibili  搜索 freeCodeCamp ...

  4. NTL密码算法开源库-大整数ZZ类(一)

    2021SC@SDUSC NTL密码算法开源库-大整数ZZ类(一) 本章综述 代码分析 贝祖公式 本章综述 大整数ZZ类主要实现了任意长度大整数表示.最大公因数.Jacobi符号和素性检验.笔者将通过 ...

  5. 【二分查找延伸--实际算法应用】数组类题目

    声明:博主是基于labuladong微信公众号文章模板驱动刷题,进行的自我刷题感悟和记录在此. 模板详情见labuladong微信公众号文章文末:原创于自己在此基础上的笔记.感悟.整合其它文献和自己的 ...

  6. 算法--------数组类---------总结

    前言: 写算法也写了十来天了,都是数组类的.今天完成了一个课题,觉得需要总结下.今天突然很遗憾的发现,自己之前写过的算法,现在自己回想起来,也不知道怎么解决. 温故而知新.决定,今天就不写算法题了,决 ...

  7. 算法题:找出整数数组中两个只出现一次的数字

    问题:一个整数数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字.要求时间复杂度为O(n),空间复杂度为O(1). 分析:这是一个很新颖的关于位运算的题目. 首先考虑这 ...

  8. c语言经典算法——查找一个整数数组中第二大数

    https://www.cnblogs.com/dootoo/p/4473958.html 题目: 实现一个函数,查找一个整数数组中第二大数. 算法思想: 设置两个变量max1和max2,用来保存最大 ...

  9. 现在有一个整数数组,已知一个数出现的次数超过了一半,请用O(n)的复杂度的算法找出这个数...

    现在有一个整数数组,已知一个数出现的次数超过了一半,请用O(n)的复杂度的算法找出这个数. 方法1:Hash链表 方法2:使用两个变量A和B,其中A存储某个数组中的数,B用来计数.开始时将B初始化为0 ...

最新文章

  1. MySQL 索引与优化
  2. python和java和scala_有没有与python3相当的scala/java收藏。国家
  3. 计算机请说明您的专业知识与技能,湖南省2012对口招生考试计算机类专业综合考试大纲...
  4. poj 3459(背包问题)
  5. time、random以及序列化模块
  6. leetcode739. 每日温度
  7. linux不支持32,Visual Studio Code 1.36发布,不再支持Linux 32位
  8. FPGA与DSP区别
  9. ubuntu 18.04 vim的安装
  10. 关于前端学习和笔试面试的总结
  11. Java float型数据判断是否相等
  12. 递推极大似然算法实现
  13. 2021-07-01事件绑定
  14. Android 提高 5 SurfaceView绘图容器的基本使用
  15. 概率论与数理统计——Chapter0
  16. step 7在win10上安装教程及安装包
  17. word的大纲视图用法你晓得了吗
  18. 拉开差距的面试题:如何设计一个电商平台积分兑换系统??
  19. thymeleaf ${xxx} Cannot resolve
  20. python 将列表按指定长度拆分

热门文章

  1. SVN:通过命令行只提交目录,并忽略其中的文件
  2. ASPNET揭秘笔记之三
  3. 在碎片化阅读充斥眼球的时代,要高效读论文
  4. 【IEEE出版】计算机多主题征稿,ICBASE 2020诚邀您投稿参会!
  5. 五个很厉害的 CNN 架构
  6. 没有基础的想转行学习Python怎么学
  7. 英伟达3080Ti、3070Ti来了!
  8. 密歇根大学团队成果:自动驾驶视觉系统——Bio-LSTM: 三维步行姿势和步态预测的生物力学反馈神经网络
  9. linux 安卓git,在Linux系统上安装Git
  10. Neural Volumes Rendering(一)