LogTrick以及优化

       LogTrick这种方法能够遍历一个数组的所有子数组,子数组元素依次根据下标顺序之间进行某种运算的所有情况,这种运算可以是与运算、或运算、求最小值运算和求最大值运算。假设这种运算是与运算,那就是求数组中子数组subArr={a1,a2,a3} ,a1&a2&a3的值,LogTrick方法可以将一个数组的所有子数组的这种连续运算结果都遍历一遍。

       首先来看代码。以与运算(&)为例:

int[] arr=new int[]{2,4,5,7};
for(int i=0;i<arr.length;i++)
{
  for(int j=i-1;j>=0;j--)
  {
    arr[j]=arr[j]&arr[i];
    //做一些其他处理
  }

}

我们看完代码之后可能会比较懵,我们来分析一下:

i=0 j=-1 不进入循环 i++

i=1 j=0 arr[0]=arr[0]&arr[1] 只运行一次,简单翻译一下,给i的前一个元素与了一个arr[i]

i=2 j=1 arr[1]=arr[1]&arr[2] j=0  arr[0]=arr[0]&arr[2] 运行了两次,给i的前两个运算与了一个arr[i]

看图可能更直观,看图也可以。下划线部分是第二层循环执行的操作,是有规律的。

可以看到每次都是给i前面的元素多一个arr[i] ,一直到遍历完最后一个元素,可以发现所有子数组的情况都被遍历了一次并得到了运算结果。

使用这样的算法可以解决一些子数组的问题,但是有些时候还需要优化可以减少一些计算量

我们以i=3为例:我们首先计算的是arr[2]=arr[2]&arr[3],如果arr[2]&arr[3]=arr[2],说明arr[3]的范围大于等于arr[2],那么我们还有没有必要计算arr[1]=arr[1]&arr[2]&arr[3]呢?

arr[1]=arr[1]&arr[2]是i=2时计算的,arr[1]现在已经是arr[1]&arr[2],要不要与上arr[3]呢?答案是不用,arr[1]&arr[2]的结果肯定是arr[2]的一部分,那么这一部分再和arr[3]与,一定还在arr[3]里面值就不会变了,因为arr[3]的范围大于等于arr[2],所以在优化时注意:arr[j]与arr[i]==arr[j]话,就不需要再给更小的j与上arr[i]了,即停止第二层循环,代码如下。

int[] arr=new int[]{2,4,5,7};
for(int i=0;i<arr.length;i++)
{
  for(int j=i-1;j>=0;j--)
  {
    if(arr[j]==(arr[j]&arr[i]))
    {
       break;
    }else{
       arr[j]=arr[j]&arr[i];
       //一些其他处理
    }
  }
}

当使用或运算为例的时候,arr[j]|arr[i]==arr[j],也不需要再给更小的j或上arr[i]了,答案自己可以想一下,是因为更小的j对应的值范围更大,再或上arr[i]肯定也不会更新了。

参考:

1. logTrick【力扣周赛 400】_哔哩哔哩_bilibili

2. 3171. 找到按位或最接近 K 的子数组 - 力扣(LeetCode)这道题灵神的题解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值