问题描述
编写一个方法reverseWords(),该方法将消息作为字符数组,并按顺序反转单词的顺序。
例如:
char[] message = { 'c','a','k','e',' ','p','o','u','n','d','s','t','l' };
因此,我们应该得到:
偷磅蛋糕
建议的实现方式是这样:
public static void reverseWords(char[] message) {
// first we reverse all the characters in the entire message array
// this gives us the right word order
// but with each word backward
reverseCharacters(message,message.length - 1);
// Now we'll make the words forward again
// by reversing each word's characters
// we hold the index of the *start* of the current word
// as we look for the *end* of the current word
int currentWordStartIndex = 0;
for (int i = 0; i <= message.length; i++) {
// found the end of the current word!
if (i == message.length || message[i] == ' ') {
// if we haven't exhausted the array,our
// next word's start is one character ahead
reverseCharacters(message,currentWordStartIndex,i - 1);
currentWordStartIndex = i + 1;
}
}
}
private static void reverseCharacters(char[] message,int leftIndex,int rightIndex) {
// walk towards the middle,from both sides
while (leftIndex < rightIndex) {
// swap the left char and right char
char temp = message[leftIndex];
message[leftIndex] = message[rightIndex];
message[rightIndex] = temp;
leftIndex++;
rightIndex--;
}
}
如您所见,它遍历了两次数组N + N,所以它将是O(n)
但是我认为使用堆栈是一种更好的方法,就像这样:
public static void reverseWords(char[] message) {
Stack<String> stack = new Stack<>();
String word = "";
int i = 0;
while (i < message.length) {
if (message[i] != ' ') {
word = word + message[i];
}
else {
stack.push(word);
word = "";
}
i++;
}
stack.push(word);
int j = 0;
while (!stack.isEmpty()) {
String wordStack = "";
wordStack = stack.pop();
for (i = 0; i < wordStack.length(); i++) {
message[j] = wordStack.charat(i);
j++;
}
if (stack.size() > 0) {
message[j] = ' ';
j++;
}
}
在这种情况下,它仅遍历数组一个,并从堆栈中插入和删除项,因此应该为O(1)。我的意思是,它也是O(n),但区别在于您只对数组进行了一次遍历。
您怎么看?我对吗?
谢谢
解决方法
您无法在O(1)中解决此任务。
为了反转消息(字符数组)中的单词,很显然,您需要至少遍历整个数组,而且可能不止一次,如我们在各种解决方案中所见。
但是,如果不实际阅读完整的数组到最后,您肯定无法反转所有单词。根据定义,将数组读到底是一个O(n)操作,n
是数组的长度。
当运行时间(或所需的步数)恒定或至少不依赖于输入长度时,运算为O(1)。就输入长度而言,读取其全部输入的方法不能为O(1)。
请注意,“关于...”部分非常重要-n
在O(n)
中的含义并不重要。
例如,在哈希表(或Java术语为HashMap)中搜索元素通常被视为O(1)操作,因为它不依赖于映射中已有的元素数量。 但是,它确实很大程度上取决于要搜索的元素的长度-它需要计算该元素的哈希值,这需要遍历元素的整个长度,因此显然这是一个O(n)操作输入的长度。 但是,由于元素本身的长度与整个哈希图的潜在大小相比通常可以忽略不计,因此该O(n)无关紧要。而且,由于在哈希映射中进行搜索实际上与映射的大小无关,因此整个事物被视为O(1)。
还要注意,O(1)并不意味着该算法对于每个给定的输入都将是快速的。它仅表示运行时间是恒定的,而不是较低的。 O(1)算法通常具有较高的固定成本和较高的常数因子,这对于较大的输入量是可以接受的,但是对于较小的输入量,具有较低固定开销的O(n)算法可能会更快。
以哈希映射为例,如果映射中有5个元素,并且您要检查映射是否包含给定值,则遍历所有5个元素的速度要快很多,很多 ,而不是使用通用算法-计算搜索到的元素的哈希值,并使用它来预测应将其存储在地图中的位置。地图中有10或50个元素也是如此,但有500万个元素是一个不同的故事,而有50亿个元素则是一个 很多 个不同的故事。
,第一个解决方案应该是更快,但是它们都在O(n)中。