C# 构造一个整数数组以获得特定的序列

C# 构造一个整数数组以获得特定的序列,c#,C#,构造以A结尾的最短整数序列, 使用以下规则: 序列的第一个元素是1,每个连续的 元素是前面任意两个元素的总和(添加单个元素) 元素本身也是允许的),每个元素都大于 上述所有要素;也就是说,序列在增加 例如,对于A=42,可能的解是[1,2,3,6,12,24, 30, 42]. 另一种可能的解决方案是[1,2,4,5,8,16,21,42] 我写了以下内容,但输入456时失败,返回[1,2,4,8,16,32,64128200256456],序列中没有可以相加得到200的数字 如何修复以下代码?

构造以A结尾的最短整数序列, 使用以下规则:

序列的第一个元素是1,每个连续的 元素是前面任意两个元素的总和(添加单个元素) 元素本身也是允许的),每个元素都大于 上述所有要素;也就是说,序列在增加

例如,对于A=42,可能的解是[1,2,3,6,12,24, 30, 42]. 另一种可能的解决方案是[1,2,4,5,8,16,21,42]

我写了以下内容,但输入456时失败,返回[1,2,4,8,16,32,64128200256456],序列中没有可以相加得到200的数字

如何修复以下代码?我做错了什么

  public static int[] hit(int n)
    {
        List<int> nums = new List<int>();

        int x = 1;

        while (x < n)
        {
            nums.Add(x);
            x = x * 2;

            if (x > n)
            {

                    nums.Add(n - (x / 2));

                nums.Add(n);
            }
        }

        nums.Sort();
        int[] arr =  nums.ToArray();
        return arr;
    }
公共静态int[]命中(int n)
{
List nums=新列表();
int x=1;
while(xn)
{
增加(n-(x/2));
添加(n);
}
}
nums.Sort();
int[]arr=nums.ToArray();
返回arr;
}

以下是我的尝试。它可能被优化了,但它显示了我的想法:

private static IEnumerable<int> OptimalSequence(int lastElement)
{
    var result = new List<int>();
    int currentElement = 1;
    do
    {
        result.Add(currentElement);
        currentElement = currentElement * 2;
    } while (currentElement <= lastElement);
    var realLastElement = result.Last();
    if (lastElement != realLastElement)
    {
        result.Add(lastElement);                
        FixCollection(result, lastElement - realLastElement);
    }
    return result;
}

private static void FixCollection(List<int> result, int difference)
{
    for (int i = 0; i < result.Count; i++)
    {
        if (result[i] == difference) break;
        if (result[i] > difference)
        {
            result.Insert(i, difference);
            FixCollection(result, difference - result[i-1]);
            break;
        }
    }
}

我知道这背后会有一个数学证明,但我的猜测是将这个数字除以2,如果它等分,重复这个过程。如果有余数,则为1。你可以得到整数商和商加1。因为保证一个在集合中,所以2个数字中较大的一个已经被处理好了。因此,只需对较小的对象重复此过程。这个问题当然意味着递归解决方案应该相对简单,所以我将把它留给海报来实现。

我想我明白了:

public Set<Integer> shortList(int n){
    Set<Integer> result = new HashSet<Integer>();
    Stack<Integer> stack = new Stack<Integer>();
    result.add(n);
    int num=n, den=0;
    while(num>1){
        while(num > den){
            num--; den++;
            if(num%den==0)
                stack.push(num);
        }//num>den
        if(!stack.isEmpty()){
            num = stack.pop();
            result.add(num);
            stack.clear();
        }else{
            result.add(num);
            result.add(den);
        }
        den=0;
    }
    return result;
}//

这是我在C++中的解决方案(可以简单地改为C):

void printSequenceTo(未签名的n)
{
如果(n==1){printf(“1”);return;}
如果(n&1){
整数因子=3;
做{
如果(n%系数==0){
printSequenceTo(n/系数*(系数-1));
系数=0;
打破
}
因子+=2;
}while(factor*factor
public static int[]命中(int n)
{
List nums=新列表();
添加(n);
int x=0;
int Right=0;
int左=0;
做
{
//偶数
如果(n%2==0)
{
x=n/2;
//除法的结果也是偶数20/2=10
如果(x%2==0 | | n>10)
{
增加(x);
n=x;
}
其他的
{
数量加(x+1);
增加(x-1);
n=x-1;
}
}
//只能被3除的数字
否则如果(n%3==0)
{
x=n/3;//46/3=155
右=x*2;//155*2=310
左=x;//155
nums.Add(右);
nums.Add(左);
n=x;
}
//只能被5除的数字
其他的
{
x=n/2;
右=x+1;
左=x;
nums.Add(右);
nums.Add(左);
n=左;
}
}而(n>2);
增加(1)项;
nums.Reverse();
int[]arr=nums.ToArray();
返回arr;
}

@FarhadTaran:到目前为止你做了什么调试?“我做错了什么?”首先,你甚至从不检查是否有任何数字可以通过加上前两个数字来获得。你的算法完全错误。你想要一种递归的方法来迭代所有可能的序列,打破那些通过你想要的数字的序列,然后取最短的序列。@FarhadTaran-你看到你开始的了吗??@FarhadTaran-现在是我)这很好,但输入310仍然失败,目标是找出最短的序列,310给出,{1,2,4,6,8,16,22,32,54,64128256310},2+6=8,4+4=8,所以这里的6可以被删除。6不能被删除,因为它是22所必需的。对不起,你是对的,但它仍然失败,54可以被删除吗?我认为它的54使它失败。64+64=128,给它自己加一个数字是允许的。对不起,54代表310=256+54。不幸的是,它不是那么简单。这个方法会给出
[1,2,3,6,7,14,15]
对于15,但是有一个
[1,2,3,6,12,15]
较短的链。不,对于15,它将给出15,8,7,4,3,2,1。但是你仍然是正确的。我错了:)你得到了相同的长度(13)像我一样输入495,但是测试站点说这太长了。有什么想法吗?我想看看他们是如何得到一个较短的答案的,我还没有看到。我会继续查找。我最终找到了[1 2 4 8 16 32 66 99 198 396 495]。然而,其他数字仍然会产生非最小序列。@BrokenGlass:不幸的是,它不是最小的。它将数字分解成素数,并为每个因子生成一个步骤序列(乘以所有以前的因子)。因此,对于35=5*7,它将[1 2 4 5]和[1 2 4 6 7]*5组合成[1 2 4 5 10 20 30 35].我想也许我应该将其分解为(2**n+1),因为我当前1025的输出非常糟糕。[1 2 4 8 16 32 33 66 99 198 396 495]看起来是最短的序列,现在如何获得它?
public Set<Integer> shortList(int n){
    Set<Integer> result = new HashSet<Integer>();
    Stack<Integer> stack = new Stack<Integer>();
    result.add(n);
    int num=n, den=0;
    while(num>1){
        while(num > den){
            num--; den++;
            if(num%den==0)
                stack.push(num);
        }//num>den
        if(!stack.isEmpty()){
            num = stack.pop();
            result.add(num);
            stack.clear();
        }else{
            result.add(num);
            result.add(den);
        }
        den=0;
    }
    return result;
}//
for 42: [1, 2, 3, 21, 6, 7, 42, 14]
for 15: [1, 2, 4, 5, 10, 15]
for 310: [1, 2, 155, 4, 5, 310, 10, 124, 62, 31, 15, 30]
void printSequenceTo(unsigned n)
{
    if (n == 1) { printf("1"); return; }
    if (n & 1) {
        int factor = 3;
        do {
            if (n % factor == 0) {
                printSequenceTo(n / factor * (factor-1));
                factor = 0;
                break;
            }
            factor += 2;
        } while (factor * factor <= n);
        if (factor) printSequenceTo(n-1);
    }
    else
        printSequenceTo(n/2);
    printf(",%u", n);
}
public static int[] hit(int n)
    {
        List<int> nums = new List<int>();

        nums.Add(n);

        int x = 0;
        int Right = 0;
        int Left = 0;

        do
        {
            //even num
            if (n % 2 == 0)
            {
                x = n / 2;

                //result of division is also even 20/2 = 10 
                if (x % 2 == 0 || n>10 )
                {

                    nums.Add(x);

                    n = x;

                }
                else
                {
                    nums.Add(x + 1);
                    nums.Add(x - 1);

                    n = x - 1;
                }

            }
                //numbers that can only be divided by 3
            else if (n % 3 == 0)
            {
                x = n / 3;//46/3 =155

                 Right = x * 2;//155*2 = 310
                 Left = x;//155

                nums.Add(Right);
                nums.Add(Left);

                n = x;

            }
                //numbers that can only be divided by 5
            else
            {
                x = n / 2;
                Right = x + 1;
                Left = x;

                nums.Add(Right);
                nums.Add(Left);

                n = Left;
            }
        } while (n > 2);

        nums.Add(1);

        nums.Reverse();

        int[] arr = nums.ToArray();


        return arr;
    }