如何优化此算法?与角色一起工作

时间:2015-09-08 02:13:19

标签: java

任务:给出两个长度相同的字符串,m和n。我们想将m修改为n。我们可以执行两项操作;

我们可以取一个当前字符串的连续段,并将字母表中的每个字母向前移动一次,或者在字母表中向后移动。

我们希望以最少的步骤完成此操作,目标是O(n)算法。

所以这是我第一次尝试它;显然甚至没有接近尽可能优化,但我有点迷失如何优化它。我不知道如何确定哪一段字母最适合。我的实现目前只能通过一个字母。

public static void shift(String m, String n) {
    char mChar[] = m.toCharArray();
    char nChar[] = n.toCharArray();

    int count = 0;
    for (int i = 0; i < m.length(); i++){
        while (mChar[i] != nChar[i]){
            if (mChar[i] - nChar[i] < 0){
                //System.out.println("SHIFT FORWARD");
                mChar[i]++;
                count++;
            }
            else{
                //System.out.println("SHIFT BACKWARD");
                mChar[i]--;
                count++;
            }
            System.out.println(mChar[i]);
        }
    }
    System.out.println(mChar);
    System.out.println(count);
}

这个算法的时间复杂度是多少? For循环使其处于最小O(n),而在最坏的情况下while循环可以运行25次(如果我们有'y'并且想要'a')。我对这个想法是对的吗?

2 个答案:

答案 0 :(得分:5)

由于你应该学习如何编程,我不会给你代码,在这种情况下,我可以帮助你使用正确的算法。

我将通过示例来做到这一点:

shift( "AAAAZZZZ", "BCDBZYYX" )

此处的目标是最小化移位操作的数量,因此您需要优化移位的块大小。

首先,确定每个角色所需的轮班数量:

A  A  A  A  Z  Z  Z  Z
B  C  D  B  Z  Y  Y  X
+1 +2 +3 +1 0  -1 -1 -2

从第一个位置开始,如果移位为正,则找到最大的连续正移位块。如果为负,则找出负移位块。申请轮班。重复到零,然后转到下一个字符。

1:索引0到3,向上移动:

B  B  B  B  Z  Z  Z  Z
0  +1 +2 0  0  -1 -1 -2

2:索引1到2,向上移动:

B  C  C  B  Z  Z  Z  Z
0  0  +1 0  0  -1 -1 -2

3:指数2,向上移动:

B  C  D  B  Z  Z  Z  Z
0  0  0  0  0  -1 -1 -2

4:索引5到7,向下移动:

B  C  D  B  Z  Y  Y  Y
0  0  0  0  0  0  0  -1

5:指数7,向下移动:

B  C  D  B  Z  Y  Y  X
0  0  0  0  0  0  0  0

完成5班制操作。

<强>更新

优化:程序不需要&#34;识别班次数&#34;在前面,或根本没有。这主要是为了帮助说明算法。

答案 1 :(得分:1)

虽然@Andreas的答案是可行的,但它不是O(N)。你想考虑最糟糕的情况,然后你会在细节中详细说明......

如何实施Andreas的答案

你需要知道间隙的大小,所以不是它改变索引的地方,而是块本身。有2个临时变量 - &gt; int startIndex, endIndex ...

首先

startIndex = 0, endIndex = -1,然后当您看到符号更改后,更改endIndex = i,在i-startIndex附加内容中记录该段长blockSize[] ...

然后当您看到其他更改startIndex = endIndexendIndex = i时,请在i-startIndex附加内容中记录blockSize[] ...

完成后,产生答案的代码块就像这样......

思维...

“我需要增加...最后4个块...让我们通过我们的数组,这可能是大小N,让我们看看..好吧最后4个是最大的块,现在让我们去增加最后4个”

现在为什么那么糟糕?

每次进行递增过程时,你需要经历那个大小为N的数组,这就是为什么它会导致N ^ 2,你明白我的意思吗?对于大哦,你总是需要考虑字面上最坏的情况,在你的情况下是

[1, -1, 1, -1, 1, -1]
那你会做什么?您将创建一个间隙大小数组

[1,1,1,1,1,1]

然后你必须经过这些间隙大小数组N次以找到最大尺寸,实际上是其中任何一个,所以你会经过N次通过N尺寸,交替阵列找到最大尺寸N ^ 2

这是另一种方法,但我不能完全确定它是O(N)还是O(N * k),其中k是将一个字母移一个所需的进程数(因为你)指定)。

[1, -1, 1, -1, 1, -1]
remove 1 from everything
[0, -2, 0, -2, 0, -2]
next time you remove 2 from everything EXCLUDING the 0's
(keep track of the 0's in another array as a flag)
[0,0,0,0,0,0] is your 2nd run through of the array
so 2 shifting operations as opposed to 36

当然,这样做我的方法也是最糟糕的情况,如下所示:

[1, 4, 12, -3, -2, 3] let's say... 
1st. [0,3,11,-4,-3,2]
2nd. [0,0,8,-7,-6,-1]
3rd. [0,0,0,-15,-14,-9]

这将导致总共6次操作,但是增量的指数在过去的3中几乎翻了两倍。我不知道你是否直接从 - &gt; z,或a-> b-> c ...如果是前者,那么我认为雪崩效应不会很大。

我想不出除此之外的任何O(N)操作,这需要k是常数。

当有人回答关于大O计算速度的问题时,你应该总是想到这句话:

  

通常仅以大O表示法描述函数   提供函数增长率的上限。关联的   使用符号,使用大O表示法是几个相关的符号   o,Ω,ω和Θ,用于描述渐近增长的其他种类界限   率。 - 维基百科

虽然@ Andrea的答案很优雅,平均而言可能表现良好,但并非O(N),因为增长率的上限可能远高于您的预期。