原创

剑指Offer面试题:34.翻转单词顺序VS左旋转字符串

一、题目一:翻转单词顺序

1.1 题目说明

题目一:输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串"I am a student.",则输出"student. a am I"。

1.2 解题思路

  第一步翻转句子中所有的字符。比如翻转"I am a student."中所有的字符得到".tneduts a ma I",此时不但翻转了句子中单词的顺序,连单词内的字符顺序也被翻转了。

  这个步骤我们大多数都很熟悉,看看下面这个Reverse方法,是不是非常熟悉?

    public static void Reverse(char[] array, int start, int end)
    {
        if (array == null || start < 0 || end > array.Length - 1)
        {
            return;
        }

        while (start < end)
        {
            char temp = array[start];
            array[start] = array[end];
            array[end] = temp;

            start++;
            end--;
        }
    }

  第二步再翻转每个单词中字符的顺序,就得到了"student.a am I"。这正是符合题目要求的输出。因此,我们可以将上述思路实现为以下代码:

    public static string ReverseSentense(string sentense)
    {
        if (string.IsNullOrEmpty(sentense))
        {
            return null;
        }

        char[] array = sentense.ToCharArray();
        int start = 0;
        int end = array.Length - 1;

        // Step1.先翻转整个句子
        Reverse(array, start, end);
        // Step2.再翻转句中的每个单词
        start = end = 0;
        while (start < array.Length)
        {
            if (array[start] == ' ')
            {
                start++;
                end++;
            }
            else if (end == array.Length || array[end] == ' ')
            {
                Reverse(array, start, --end);
                start = end + 1;
                end++;
            }
            else
            {
                end++;
            }
        }

        return new string(array);
    }

1.3 单元测试

  (1)测试用例

    // 功能测试,句子中有多个单词
    [TestMethod]
    public void ReverseTest1()
    {
        string input = "I am a student.";
        string actual = ReverseWordsHelper.ReverseSentense(input);
        string expected = "student. a am I";

        Assert.AreEqual(actual, expected);
    }

    // 功能测试,句子中只有一个单词
    [TestMethod]
    public void ReverseTest2()
    {
        string input = "Wonderful";
        string actual = ReverseWordsHelper.ReverseSentense(input);
        string expected = "Wonderful";

        Assert.AreEqual(actual, expected);
    }

    // 边界值测试,测试空字符串
    [TestMethod]
    public void ReverseTest3()
    {
        string input = "";
        string actual = ReverseWordsHelper.ReverseSentense(input);

        Assert.AreEqual(actual, null);
    }

    // 边界值测试,字符串中只有空格
    [TestMethod]
    public void ReverseTest4()
    {
        string input = "   ";
        string actual = ReverseWordsHelper.ReverseSentense(input);
        string expected = "   ";

        Assert.AreEqual(actual, expected);
    }

    // 鲁棒性测试
    [TestMethod]
    public void ReverseTest5()
    {
        string actual = ReverseWordsHelper.ReverseSentense(null);

        Assert.AreEqual(actual, null);
    }

  (2)测试结果

  ①测试用例通过情况

  ②代码覆盖率统计

二、题目二:左旋转字符串

2.1 题目说明

题目二:字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如输入字符串"abcdefg"和数字2,该函数将返回左旋转2位得到的结果"cdefgab"。

2.2 解题思路

  这两个问题是非常相似的,我们同样可以通过翻转字符串的办法来解决第二个问题。

  以"abcdefg"为例,我们可以把它分为两部分。由于想把它的前两个字符移到后面,我们就把前两个字符分到第一部分,把后面的所有字符都分到第二部分。我们先分别翻转这两部分,于是就得到"bagfedc"。接下来我们再翻转整个字符串,得到的"cdefgab"刚好就是把原始字符串左旋转2位的结果。

  通过分析可以发现,我们只需要调用三次Reverse方法就可以实现字符串的左旋转功能

    public static string LeftRotateString(string str, int num)
    {
        if (string.IsNullOrEmpty(str))
        {
            return null;
        }

        int strLength = str.Length;
        char[] array = str.ToCharArray();

        if (strLength > 0 && num > 0 && num < strLength)
        {
            int firstStart = 0;
            int firstEnd = num - 1;
            int secondStart = num;
            int secondEnd = strLength - 1;

            // 翻转字符串的前面n个字符
            Reverse(array, firstStart, firstEnd);
            // 翻转字符串的后面部分
            Reverse(array, secondStart, secondEnd);
            // 翻转整个字符串
            Reverse(array, 0, strLength - 1);
        }

        return new string(array);
    }

2.3 单元测试

  (1)测试用例

    // 功能测试
    [TestCategory("LeftRotate")]
    [TestMethod]
    public void RotateTest1()
    {
        string input = "abcdefg";
        string actual = ReverseWordsHelper.LeftRotateString(input, 2);
        string expected = "cdefgab";

        Assert.AreEqual(actual, expected);
    }

    // 边界值测试
    [TestCategory("LeftRotate")]
    [TestMethod]
    public void RotateTest2()
    {
        string input = "abcdefg";
        string actual = ReverseWordsHelper.LeftRotateString(input, 1);
        string expected = "bcdefga";

        Assert.AreEqual(actual, expected);
    }

    // 边界值测试
    [TestCategory("LeftRotate")]
    [TestMethod]
    public void RotateTest3()
    {
        string input = "abcdefg";
        string actual = ReverseWordsHelper.LeftRotateString(input, 6);
        string expected = "gabcdef";

        Assert.AreEqual(actual, expected);
    }

    // 鲁棒性测试
    [TestCategory("LeftRotate")]
    [TestMethod]
    public void RotateTest4()
    {
        string actual = ReverseWordsHelper.LeftRotateString(null, 6);

        Assert.AreEqual(actual, null);
    }

    // 鲁棒性测试
    [TestCategory("LeftRotate")]
    [TestMethod]
    public void RotateTest5()
    {
        string input = "abcdefg";
        string actual = ReverseWordsHelper.LeftRotateString(input, 0);
        string expected = "abcdefg";

        Assert.AreEqual(actual, expected);
    }

    // 鲁棒性测试
    [TestCategory("LeftRotate")]
    [TestMethod]
    public void RotateTest6()
    {
        string input = "abcdefg";
        string actual = ReverseWordsHelper.LeftRotateString(input, 7);
        string expected = "abcdefg";

        Assert.AreEqual(actual, expected);
    }

  (2)测试结果

  ①用例通过情况

  ②代码覆盖率

 

正文到此结束
本文目录