【发布时间】:2016-12-28 22:33:41
【问题描述】:
所以我一直在经历各种问题来复习即将到来的面试,我遇到的一个问题是确定两个字符串是否相互旋转。显然,我不是第一个解决这个问题的人。事实上,我确实发现我解决这个问题的想法似乎与this question 中采用的方法相似。
完全披露:我在 Math SE 上确实有一个 related question,它从更数学的角度关注属性(尽管值得注意的是,我试图在此背后制定想法的方式最终由于某些原因是不正确的那里有解释)。
这就是想法(这类似于链接问题中采用的方法):假设您有一个字符串abcd 和旋转cdab。显然,cd 和 ab 都是 cdab 的子字符串,但如果将它们连接在一起,则会得到 abcd。
所以基本上,旋转只是需要将子字符串从字符串的末尾移动到开头(例如,我们通过将 cd 从字符串的末尾移动到字符串的开头来从 abcd 构造 cdab )。
我想出了一种在非常有限的情况下工作的方法(如果两个子字符串都由连续的字母组成,就像他们在示例中所做的那样),但否则它会失败(我给出了一个通过和失败的例子代码下方的案例和输入/输出)。我试图弄清楚是否有可能(甚至值得)尝试修复它以在一般情况下工作。
public bool AreRotations(string a, string b)
{
if (a == null)
throw new ArgumentNullException("a");
else if (b == null)
throw new ArgumentNullException("b");
else if (a.Trim().Length == 0)
throw new ArgumentException("a is empty or consists only of whitespace");
else if (b.Trim().Length == 0)
throw new ArgumentException("b is empty or consists only of whitespace");
// Obviously, if the strings are of different lengths, they can't possibly be rotations of each other
if (a.Length != b.Length)
return false;
int[] rotationLengths = new int[a.Length];
/* For rotations of length -2, -2, -2, 2, 2, 2, the distinct rotation lengths are -2, 2
*
* In the example I give below of a non-working input, this contains -16, -23, 16, 23
*
* On the face of it, that would seem like a useful pattern, but it seems like this
* could quickly get out of hand as I discover more edge cases
*/
List<int> distinctRotationLengths = new List<int>();
for (int i = 0; i < a.Length; i++)
{
rotationLengths[i] = a[i] - b[i];
if (i == 0)
distinctRotationLengths.Add(rotationLengths[0]);
else if (rotationLengths[i] != rotationLengths[i - 1])
{
distinctRotationLengths.Add(rotationLengths[i]);
}
}
return distinctRotationLengths.Count == 2;
}
现在是示例输入/输出:
StringIsRotation rot = new StringIsRotation();
// This is the case that doesn't work right - it gives "false" instead of "true"
bool success = rot.AreRotations("acqz", "qzac");
// True
success = rot.AreRotations("abcdef", "cdefab");
// True
success = rot.AreRotations("ablm", "lmab");
// False, but should be true - this is another illustration of the bug
success = rot.AreRotations("baby", "byba");
// True
success = rot.AreRotations("abcdef", "defabc");
//True
success = rot.AreRotations("abcd", "cdab");
// True
success = rot.AreRotations("abc", "cab");
// False
success = rot.AreRotations("abcd", "acbd");
// This is an odd situation - right now it returns "false" but you could
// argue about whether that's correct
success = rot.AreRotations("abcd", "abcd");
是否有可能/值得挽救这种方法并让它仍然是 O(n),或者我应该只使用我链接到的帖子中描述的方法之一? (请注意,这实际上不是生产代码或作业,纯粹是为了我自己的学习)。
编辑:基于 cmets 进一步澄清,这里实际上有两个问题 - 首先,这个算法是否可以修复?其次,它是否甚至值得修复它(或者我应该尝试另一种方法,如答案中描述的方法或我链接到的其他问题)?我想到了一些可能的修复方法,但它们都涉及不优雅的特殊情况推理或使该算法 O(n^2),这两者都会首先扼杀算法的要点。
【问题讨论】:
-
你能按字母顺序对两个字符串中的所有字符进行排序并进行比较吗?
-
@apocalypse 所有旋转都是字谜,但并非所有字谜都是旋转。在字符串轮换中,顺序很重要。
-
在您的示例中,您有
success = rot.AreRotations("abcd", "cdab");= true 和 false!还有你到底在问什么?修复你的算法,或者什么是最好的算法? -
我不明白,为什么 rot.AreRotations("baby", "byba") 是假的?它旋转了 2 个点。
-
@user3589054 很抱歉造成混乱,这实际上是错误的说明,我会澄清评论