赞
踩
采用原地Hash的方式做,代码如下:
class Solution { public List<Integer> findDuplicates(int[] nums) { List<Integer> ans = new ArrayList<Integer>(); for(int i = 0;i<nums.length;i++){ int value = nums[i]; int index = value-1; if(index == i){ continue; } if(nums[i] == nums[index]){ continue; } swap(nums,i,index); i--; } for(int i = 0;i<nums.length;i++){ //找下标 if(i != nums[i]-1){ ans.add(nums[i]); } } return ans; } public void swap(int[] nums,int a,int b){ int temp = nums[a]; nums[a] = nums[b]; nums[b] = temp; } }
使用动态规划+三指针法(多路归并),最优子结构为:
dp[i] = Math.min(Math.min(num2,num3),num5);
class Solution { public int nthUglyNumber(int n) { int ptr2 = 1; int ptr3 = 1; int ptr5 = 1; int[] dp = new int[n+1]; dp[1] = 1; for(int i = 2;i<=n;i++){ int num2 = dp[ptr2]*2; int num3 = dp[ptr3]*3; int num5 = dp[ptr5]*5; dp[i] = Math.min(Math.min(num2,num3),num5); if(dp[i] == num2){ ptr2++; } if(dp[i] == num3){ ptr3++; } if(dp[i] == num5){ ptr5++; } } return dp[n]; } }
文件分配给磁盘有三种分配方式:连续分配|链接分配|索引分配
对标数组中查找、新增元素
寻道时间最短 访问容易 有大量外部碎片产生(内存的特性)
解决方案为合并磁盘空间,但是这样就算解决了外部碎片,开销也过于大
对标链表中查找、新增元素
寻道时间比较长(磁头寻道时间较长)
创建指针会有单独的内存开销
没有外部碎片
解决开销问题:将多个块组成簇,这种方法会增加内部碎片
对标hash表中查找、新增元素
通过加大空间消耗来使链接分配的方式折中寻道时间(增加索引块)
但是索引块对空间的占用比较大
另外对索引块大小也有考究,不能过小或过大
目前的链接目的有:把索引块做成链接块,本身就可以读的话,就可以减少专门作索引块的压力
使用多级索引
位图,就是用每一位来存放某种状态,适用于大规模数据,但数据状态又不是很多的情况。通常是用来判断某个数据存不存在的。
举个例子,如下图,如果我们想要存放 0,2,4,5,10,11,12,14,15这几个数字,如果采用普通存储方式,若4位表示一个数字,这9个数字需要4*9=36位,至少36位才能存储这些数据。
如果采用位图的方式,只需要上图的16位就能存储这9个数字。
查找的时候,只需要查找这个位的数是1还是0即可,就可以确定该数存在不存在。
当数量足够大时候,不光大大压缩了存储空间,查找速率也极快,可以说是O(1)。
bitmap是redis的一种扩展数据类型,主要用于二值状态统计,比如公司记录员工打卡记录,电商网站记录用户登录行为,积分商城记录用户签到情况。
例子转自知乎:redis灵魂拷问:聊一聊bitmap使用
下面我们看一下bitmap的使用。
员工打卡
假如一个公司有100个员工,公司要对员工11月份的打卡行为进行统计,我们可以为11月份每一天分配一个bitmap,这个bitmap保存100个bit位,来记录员工的打卡行为。
注意:bitmap偏移量从0开始,所以100个bit位是从0~99,依次记录1-100号员工。
我们定义bitmap的key格式为:signed:20201101,记录2020年11月1日的打卡情况。下面代码是员工打卡和查询员工打卡情况:
/** * SETBIT命令 * 员工打卡 * 时间复杂度:O(1) */ public void sign(String key, int employeeNumber){ redisTemplate.opsForValue().setBit(key, employeeNumber - 1, true); } /** * GETBIT命令 * 查看员工打卡情况 * 时间复杂度:O(1) */ public boolean isSigned(String key,int employeeNumber){ return redisTemplate.opsForValue().getBit(key, employeeNumber - 1); }
我们可以查看某一天的打卡总人数,代码如下,入参:“signed:20201101”:
/**
* BITCOUNT命令
* 查看某一天的打卡人数
* 时间复杂度:O(N)
*/
public Long signedCount(String key){
return (Long) redisTemplate.execute((RedisCallback<Long>) conn -> conn.bitCount(key.getBytes()));
}
那如果想看当月没有迟到过的员工呢?这个时候就要用到交集了,对当月每天的bitmap做交集,值为1的员工就是没有迟到过的。
这时就要用到bitmap的聚合运算了,命令BITOP, 支持AND(与)、OR(或), XOR(异或) and NOT(非)运算,除了NOT后面跟一个bitmap外,其他3种聚合运算后面都可以跟多个bitmap,命令如下:
BITOP AND destkey srckey1 srckey2 srckey3 … srckeyN
BITOP OR destkey srckey1 srckey2 srckey3 … srckeyN
BITOP XOR destkey srckey1 srckey2 srckey3 … srckeyN
BITOP NOT destkey srckey
bitmap广泛地运用在二值计算的场景,对于一个二值状态只用一个bit位就可以,非常节约内存。比如我们对一个10亿的用户进行日活计算,占用的空间为10亿/8/1024/1024=120M
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。