我编写的代码将为字符串“ aabbcc”返回“ abc”,但是如果有更多的字母(如“ aaa”),它将返回“ aa”而不是一个。
这是我编写的代码。
void Ponavljanje(char *s, char *p) {
int i, j = 0, k = 0, br = 0, m = 0;
for (i = 0; i < strlen(s) - 1; i++) {
for (j = i + 1; j < strlen(s); j++) {
if (s[i] == s[j]) {
br++;
if (br == 1) {
p[k++] = s[i];
}
}
}
br = 0;
}
p[k] = '\0';
puts(p);
}
对于“ 112233”输出应为“ 123”,对于“ 11122333”输出也应为“ 123”。
答案 0 :(得分:1)
做这项工作的复杂度为O(n) 我想编程可以给rmg
void Ponavljanje(char *s,char *p)
{
char n[256] = {0};
int i = 0;
while (*s) {
switch (n[(unsigned char) *s]) {
case 0:
n[(unsigned char) *s] = 1;
break;
case 1:
p[i++] = *s;
n[(unsigned char) *s] = 2;
}
s += 1;
}
p[i] = 0;
puts(p);
}
答案 1 :(得分:1)
避免重复调用strlen(s)
。弱小的编译器可能看不到s
不变,并多次调用strlen(s)
,每次调用都保证了n
操作的成本-效率很低。 @arkku。 1 而是在检测到空字符时停止迭代。
将所有char
的标志的布尔值列表初始化为false。出现字符时,设置标志以防止后续使用。将列表索引为char
可能为负时要小心。
使用const char *s
可以扩大分配范围,并有助于编译器优化。
示例:
#include <stdbool.h>
#include <limits.h>
void Ponavljanje(const char *s, char *p) {
const char *p_original = p;
bool occurred[CHAR_MAX - CHAR_MIN + 1] = { 0 }; // all values set to 0 (false)
while (*s) {
if (!occurred[*s - CHAR_MIN]) {
occurred[*s - CHAR_MIN] = true;
*p++ = *s;
}
s++;
}
*p = '\0';
puts(p_original);
}
1 @wrongway4you的评论是,许多编译器可能会假设字符串没有变化,并优化了重复的strlen()
调用。兼容编译器无法这样做,尽管没有restrict
,除非知道,在所有调用中,s
和p
不会重叠。否则,编译器需要假设p
可能影响s
,并保证重复进行strlen()
调用。
答案 2 :(得分:0)
虽然内部循环检查br
仅在第一次重复时复制输出,但在以后的迭代中,外部循环仍会越过s
中的每个重复。因此,br
重置后,每次出现相同的字符都会运行一个单独的内部循环。
使用aaa
作为输入,第一个a
和第二个aa
都会使内部循环找到重复,给您clone
。实际上,输出中每个字符总是比输入少一个出现,这意味着它只能在输入中出现1或2个出现(输出中分别出现0和1个出现)。
答案 3 :(得分:0)
这是不管顺序如何都可以起作用的东西:
#include <stdio.h>
#include <string.h>
void
repeat(char *s, char *p)
{
int slen;
int sidx;
int pidx;
int plen;
int schr;
slen = strlen(s);
plen = 0;
for (sidx = 0; sidx < slen; ++sidx) {
schr = s[sidx];
// look for duplicate char
int dupflg = 0;
for (pidx = 0; pidx < plen; ++pidx) {
if (p[pidx] == schr) {
dupflg = 1;
break;
}
}
// skip duplicate chars
if (dupflg)
continue;
p[plen++] = schr;
}
p[plen] = 0;
puts(p);
}
int
main(void)
{
char p[100];
repeat("112233",p);
repeat("123123",p);
return 0;
}
注意:正如其他人所提到的,strlen
不应放在for
的循环条件子句中,因为s
的长度是不变的]。将strlen(s)
保存到一个单独的变量中并循环到该限制
以下是使用直方图的其他/更快的版本,因此只需要一个循环:
#include <stdio.h>
#include <string.h>
void
repeat(char *s, char *p)
{
char dups[256] = { 0 };
int slen;
int sidx;
int pidx;
int plen;
int schr;
slen = strlen(s);
sidx = 0;
plen = 0;
for (sidx = 0; sidx < slen; ++sidx) {
schr = s[sidx] & 0xFF;
// look for duplicate char
if (dups[schr])
continue;
dups[schr] = 1;
p[plen++] = schr;
}
p[plen] = 0;
puts(p);
}
int
main(void)
{
char p[100];
repeat("112233",p);
repeat("123123",p);
return 0;
}
更新#2:
我建议迭代直到终止的NUL字节
好的,这是一个完整的指针版本,其速度与我所知道的一样快:
#include <stdio.h>
#include <string.h>
void
repeat(char *s, char *p)
{
char dups[256] = { 0 };
char *pp;
int schr;
pp = p;
for (schr = *s++; schr != 0; schr = *s++) {
schr &= 0xFF;
// look for duplicate char
if (dups[schr])
continue;
dups[schr] = 1;
*pp++ = schr;
}
*pp = 0;
puts(p);
}
int
main(void)
{
char p[100];
repeat("112233",p);
repeat("123123",p);
return 0;
}
答案 4 :(得分:0)
如果您只想删除连续的双字母,那么此功能就足够了,问题中给出的示例将适用:
#include <stdio.h>
void Ponavljanje(char *s,char *p)
{
char dd = '\0';
char *r;
if(s == NULL || p == NULL)
return;
r = p;
while(*s){
if(*s != dd){
*r = *s;
dd = *s;
r++;
}
s++;
}
*r = '\0';
puts(p);
}
int main(void)
{
char s[20] = "1111332222";
char p[20];
Ponavljanje(s,p);
}