这里显示了5个不同的集合。 S1包含1.下一组S2从S1计算,考虑以下逻辑:
现在,如果给出n作为输入,那么我们必须显示集合Sn的所有元素。 显然,有可能在O(n)时间内解决问题。
我们可以将所有中间元素计算为(2 ^(n-1) - 前一组的中间元素+ 1),其中s1 = {1}是基本情况。以这种方式O(n)时间我们将得到所有中间元素直到第(n-1)组。因此,第(n-1)组的中间元素是第n组集合的第一个元素。 (第(n-1)组的中间元素+第(n-2)组的中间元素)是第n组的中间第二元素。通过这种方式,我们将获得第n组的所有元素。 所以它需要O(n)时间。
这里是我编写的完整java代码:
public class SpecialSubset {
private static Scanner inp;
public static void main(String[] args) {
// TODO Auto-generated method stub
int N,fst,mid,con=0;
inp = new Scanner(System.in);
N=inp.nextInt();
int[] setarr=new int[N];
int[] midarr=new int[N];
fst=1;
mid=1;
midarr[0]=1;
for(int i=1;i<N;i++)
{
midarr[i]=(int) (Math.pow(2, i)-midarr[i-1]+1);
}
setarr[0]=midarr[N-2];
System.out.print(setarr[0]);
System.out.print(" ");
for(int i=1,j=N-3;i<N-1;i++,j--)
{
setarr[i]=setarr[i-1]+midarr[j];
System.out.print(setarr[i]);
System.out.print(" ");
}
setarr[N-1]=setarr[N-2]+1;
System.out.print(setarr[N-1]);
}
}
以下是问题的链接:
https://www.hackerrank.com/contests/projecteuler/challenges/euler103
是否可以用少于O(n)的时间来解决问题?
答案 0 :(得分:3)
让 i j 成为第j组中的第i个数字。
我还将b j 定义为j-2
- 集的第一个数字。这是证明的序列。 -2是Narayana-Zidek-Capell序列中的第一个和第二个1
。
问题陈述没有说明“中心数”对于偶数长度集(真正的列表,但无论如何)是什么,但在这种情况下它们似乎意味着“正确的中心”。当我在下面使用它时,我将以粗体表示规则编号。
第一步是通过稍微展开递归并替换b
来为 i n 制定一个稍微复杂的公式:
j
[0 ... i-1]
醇>
接下来,我们考虑b n 的两种情况 - 一种n
为奇数,一种n
为偶数。
即便如此:
b 2n + 2 = a 1 2n =
2 = a ceil( 2n + 1 / 2 ) 2n-1 = a n + 1 2n-1 =
3 = a 1 2n-1 + a n 2n-2 = <登记/>
2,4 = b 2n + 1 + a 1 2n-1 =
5 = 2 * b 2n + 1
奇怪的案例:
b 2n + 1 = a 1 2n-1 =
2 = a ceil( 2n / 2 ) 2n-2 = a < sup> n 2n-2 =
3 = a 1 2n-2 + a n-1 2n-3 =
4 = 2 * b 2n +(a n-1 2n-3 - a 1 < / sup> 2n-2 )=
2 = 2 * b 2n +(a n-1 2n-3 - a n < / sup> 2n-3 )=
5 = 2 * b 2n - b n
这些规则是确切的序列定义,并提供了一种在线性时间内生成n
集的方法(与依次生成每个集时的二次方相对)
答案 1 :(得分:1)
集合中的最小数字似乎是Narayana-Zidek-Capell numbers
1, 1, 2, 3, 6, 11, 22, ...
通过反向重复添加这些数字,从第一个数字中获得其他数字。
例如,
S6 = {11, 17, 20, 22, 23, 24}
+6 +3 +2 +1 +1
使用该链接中找到的Narayana-Zidek-Capell序列的重复,我已设法为O(n)
时间内运行的此问题生成解决方案。这是Java的解决方案。由于n <= 32
溢出,它仅适用于int
,但可以使用BigInteger
来编写更高的值。
static Set<Integer> set(int n) {
int[] a = new int[n + 2];
for (int i = 1; i < n + 2; i++) {
if (i <= 2)
a[i] = 1;
else if (i % 2 == 0)
a[i] = 2 * a[i - 1];
else
a[i] = 2 * a[i - 1] - a[i / 2];
}
Set<Integer> set = new HashSet<>();
int sum = 0;
for (int i = n + 1; i >= 2; i--) {
sum += a[i];
set.add(sum);
}
return set;
}
我现在无法证明为什么这与问题中的设置相同,但我正在研究它。但是我检查了所有n <= 32
这个算法给出了与“明显”算法相同的集合,所以我有理由相信它是正确的。