在Cracking the coding interview
读一本名为Gayle Laakmann
的书时,我遇到了这个问题
设计算法并编写代码以删除重复的字符 在不使用任何额外缓冲区的字符串中。注意:一两个 其他变量很好。数组的额外副本不是。
和此代码: -
public static void removeDuplicates(char[] str) {
if (str == null) {
return;
}
int len = str.length;
if (len < 2) {
return;
}
int tail = 1;
for (int i = 1; i < len; ++i) {
int j;
for (j = 0; j < tail; ++j) {
if (str[i] == str[j]) {
break;
}
}
if (j == tail) {
str[tail] = str[i];
++tail;
}
}
str[tail] = 0;
}
应该从数组中删除重复的字符。我不安静似乎通过一次又一次地替换相同的角色来理解算法正在做什么。我认为只有我觉得算法不起作用,但实际上当我运行这个代码时,它给了我错误的输出。这是书中的严重错误还是我不明白这个问题?
答案 0 :(得分:7)
Algo似乎正在工作,但没有清除剩余的角色。 将代码更改为以下内容并且有效: 注意:替换为:
str[tail] = 0;
with:
for(; tail < len;tail++){
str[tail] = 0;
}
public static void removeDuplicates(char[] str) {
if (str == null) {
return;
}
int len = str.length;
if (len < 2) {
return;
}
int tail = 1;
for (int i = 1; i < len; ++i) {
int j;
for (j = 0; j < tail; ++j) {
if (str[i] == str[j]) {
break;
}
}
if (j == tail) {
str[tail] = str[i];
++tail;
}
}
for(; tail < len;tail++){
str[tail] = 0;
}
}
答案 1 :(得分:2)
使用位向量的解决方案。
时间:O(n),其中n = length of the string
空间:O(1)
void removeduplicatas(char str[]){
int i, checker = 0, bitvalue = 0, value = 0, tail = 0;
i = 0;
tail = 0;
while(str[i]){
value = str[i] - 'a';
bitvalue = 1 << value;
if((checker & bitvalue) == 0 ){
str[tail++] = str[i];
checker |= bitvalue;
}
i++;
}
str[tail] = '\0';
}
答案 2 :(得分:1)
在Java中,数组的大小是固定的。因此,如果调用函数找到任何重复项,则无法更改输入数组的大小。您的函数只是将子数组的起始索引复制到0
。因此,当您在调用函数中打印数组内容时,已生成的元素0
不会被打印,但是后面的元素(如果有)会被打印。
YoK的答案使子数组的所有元素都重复为0.因此,当您在调用函数中打印它时,不会打印重复项。但是你需要记住,数组的大小仍然没有改变。
或者,您可以返回具有唯一字符的子数组的大小。在您的情况下,tail
。
另一种选择是将输入作为StringBuffer
传递并按原样进行更改:
public static void removeDuplicates(StringBuffer str) {
int len = str.length();
// if the string as less than 2 char then it can't have duplicates.
if (len < 2) {
return;
}
// fist character will never be duplicate.
// tail is the index of the next unique character.
int tail = 1;
// iterate from 2nd character.
for (int i = 1; i < len; ++i) {
int j;
// is char at index i already in my list of uniq char?
for (j = 0; j < tail; ++j) {
if (str.charAt(i) == str.charAt(j)) {
break;
}
}
// if no then add it to my uniq char list.
if (j == tail) {
str.setCharAt(tail, str.charAt(i));
// increment tail as we just added a new ele.
++tail;
}
}
// at this point the characters from index [0,tail) are unique
// if there were any duplicates they are between [tail,input.length)
// so truncate the length of input to tail.
str.setLength(tail);
}
答案 3 :(得分:1)
这是一个使用C ++和递归来循环遍历字符串的每个字符并使用固定宽度char中的bitstring方法的解决方案。您需要确保固定的宽字符串长于要检查的必要k类型字符。
#include <cstdint>
#include <iostream>
bool CheckUniqueChars(char *string, uint32_t index, uint32_t checker){
char character = string[index];
if(character=='\0'){
return true;
}else{
int value = character - 'a';
if((checker&(1<<value))>0){
return false;
}else{
checker |= (1<<value);
return CheckUniqueChars(string,++index,checker);
}
}
}
int main(int argc, char *argv[]){
char *string = argv[1];
uint32_t idx=0,checker=0;
if(CheckUniqueChars(string,idx,checker)){
std::cout << "all characters are unique" << std::endl;
}else{
std::cout << "there are duplicate characters" << std::endl;
}
return 0;
}
答案 4 :(得分:0)
我使用YoK提供的即兴代码来避免使用
for(; tail < len;tail++){
str[tail] = 0;
}
相反,我们可以在第一个循环中设置空白。
public static void removeDuplicates(char[] str){
if (str == null) {
return;
}
int len = str.length;
if (len < 2) {
return;
}
int tail = 1;
for(int i=1;i<len;++i){
int j;
for(j=0;j<tail;++j){
if(str[i] == str[j]) break;
}
if(j==tail){
str[tail] = str[i];
if(i!=tail)str[i]=0;
++tail;
}else{
str[i]=0;
}
}
}