Swarm 发表于 2019-4-13 12:28:19

C\C++数字排列问题

输入任意正整数n(n>=3),要求输出由1,1,2,2,3,3,......,n,n等2n个数组成的数列,使得:
    两个“1”之间有1个数
    两个“2”之间有2个数
    两个“3”之间有3个数
    ......
    两个“n”之间有n个数
    如输入3,则输出231213或312132

可能没有或者有多种排列方式,要求全部输出。

我能想到的唯一思路是将这2n个数字全排列,然后把不符合要求的排序剔除掉。虽然空间复杂度只有O(n),但这样的算法时间复杂度足足有O(n!),这显然是不可接受的。希望有大家能帮萌新解决一下这个问题。谢谢大家!

千公子 发表于 2019-4-13 16:00:23

我有一个思路,你可以参考下,比方说n=3,1[]1, 2()()2, 3{}{}{}3, 31(1)(3)2,成对出现去拼,n=4也同理41312432可以很快的拼出结果。

千公子 发表于 2019-4-13 16:07:14

你可以弄一个字符串,然后写一个函数。
void func(int n, string s){
找到s第一个空位,
放下数字n,
然后隔n个位置把n放下。
如果该位置有数字,重新寻找第一位。
}

Swarm 发表于 2019-4-14 10:19:15

千公子 发表于 2019-4-13 16:07
你可以弄一个字符串,然后写一个函数。

那这样的话是不是需要用到递归?先插入n,再插入n-1,一直到最后插入1?

千公子 发表于 2019-4-14 15:41:51

Swarm 发表于 2019-4-14 10:19
那这样的话是不是需要用到递归?先插入n,再插入n-1,一直到最后插入1?

都可以吧,但是需要回溯,也就是全排列的思想,只不过是成对的排,用这个思路应该就排除112233这种情况,

Swarm 发表于 2019-4-22 09:07:00

目前能够做到的就是这样……输入3和4都可以得到正确结果……
但当我输入5,的时候,本应该是没有结果,但是却告诉我程序运行出错……
应该有可能是内存溢出了?求大家帮忙看一下到底是怎么回事?
#include <stdio.h>
#include <stdlib.h>

#define Max 100
int array={0};
int visit={0};

typedef struct
{
        int no;
        int posi;
        int top;
}Stack;





void Inite(Stack *&s,int n)
{
        int i;
        s=(Stack *)malloc(sizeof(Stack));
        s->top=-1;
        for(i=n*2;i<Max*2;i++)
                array=-1;
}





void Destroy(Stack *&s)
{
        free(s);
}





void Push(Stack *&s,int i,int p)                //入栈,填数字,将visit记为1
{
        //入栈常规操作
        s->top++;
        s->no=i;
        s->posi=p;

        //将数字放进数组里
        array=array=i;

        //这个位置i试过了
        visit=1;
}





void Pop(Stack *&s,int n)                                //出栈,数组恢复,重置visit
{
        int i,p;
        int j,k;

        //出栈常规操作
        i=s->no;
        p=s->posi;
        s->top--;

        //将数字从数组里取出
        array=array=0;

        //将出栈元素之前的所有元素的visit重置
        for(k=0;k<i-1;k++)
                for(j=0;j<n*2;j++)
                        visit=0;
}





bool Empty(Stack *&s)
{
        return s->top==-1;
}





void PopAll(Stack *&s,int n)
{
        while(!Empty(s))
                Pop(s,n);
}





void Disp(int n)
{
        int i;
        int p,q;
        for(i=0;i<2*n;i++)
        {
                printf("%d ",array);
        }
        printf("\n");
        for(p=0;p<n-1;p++)
                for(q=0;q<2*n;q++)
                        visit=0;
        for(p=0;p<2*n;p++)
                array=0;
}





void sort(Stack *&s,int n)
{
        int i=n,p,j;
        int count=0;
        while(1)
        {
                for(i;i>0;i--)                                //i用于计数
                {
                        for(p=0;p<2*n-i-1;p++)        //p用来定位
                        {
                                if(array==0 && array==0 && visit==0)//这个位置和间隔i个位置都有空而且这个位置以前没放过
                                {
                                        Push(s,i,p);        //入栈,填数字,将visit记为1
                                        break;
                                }
                        }
                        if(p==2*n-i-1)                                //所有位置都试过一遍了
                        {
                                Pop(s,n);                        //出栈,数组恢复,重置visit
                                i+=2;                                //重新排出栈的那个元素
                        }
                }


                //判断是否要打印
                for(j=0;j<n*2;j++)
                        if(array==0)
                                goto next;
                Disp(n);
                i=n;
                PopAll(s,n);
                count++;


                //判断是否全都循环过一遍
next:        for(j=0;j<n-1;j++)
                        if(visit==0)
                                goto end;
                break;
end:        ;
        }
        if(count==0)
                printf("无\n");
}





int main()
{
        int n;
        Stack *s;
        printf("Input a number:( must more than 0 and less than 101 )\n");
        scanf("%d",&n);
        Inite(s,n);
        sort(s,n);
        Destroy(s);
        return 0;
}

千公子 发表于 2019-5-18 01:08:45

本帖最后由 千公子 于 2019-5-18 01:10 编辑

我今天做题做到了这个,就写了代码!你可以参考下!标题:扑克序列

    A A 2 2 3 3 4 4, 一共4对扑克牌。请你把它们排成一行。
    要求:两个A中间有1张牌,两个2之间有2张牌,两个3之间有3张牌,两个4之间有4张牌。

    请填写出所有符合要求的排列中,字典序最小的那个。

例如:22AA3344 比 A2A23344 字典序小。当然,它们都不是满足要求的答案

#include <iostream>

using namespace std;
struct num {
        int n;
        char c;
}A;

//结果
char arr;
// 使用过的字符标记上
bool used;
// 已经使用的字符数
int used_count = 0;
// 递归次数
int deep_num = 0;

void init() {
        for (int i = 0; i < 9; ++i) {
                arr = '\0';
                if(i<4)
                        used = false;
        }
}
void shift(int j) {
        ++deep_num;
        for (int i = j; i < 7; ++i) {

                for (int k = 0; k <= 3; ++k) {
                        if (used) continue;
                        int nextidx = i + A.n;
                        if (nextidx > 7) continue;
                        // 找到合适位置
                        if (arr == '\0' && arr == '\0') {
                                arr = A.c;
                                arr = A.c;
                                used_count += 1;
                                used = true;

                                shift(j + 1);

                                arr = '\0';
                                arr = '\0';
                                used_count -= 1;
                                used = false;
                        }
                }
        }
       
        if(used_count==4)
                cout << arr << endl;
}
int main() {
       
        A.n = 2;
        A.c = 'A';

        A.n = 3;
        A.c = '2';

        A.n = 4;
        A.c = '3';

        A.n = 5;
        A.c = '4';

        init();
        shift(0);
        cout << deep_num << endl;
        return 0;
}

思路还是上次和你说的思路!
页: [1]
查看完整版本: C\C++数字排列问题