Arrays O(n)就地压缩算法;“相同字母模式”;
这是我在这里的第一篇文章,所以我希望我能遵守规则。 几天前我参加了一次工作面试,我遇到了一个我能解决的问题(直到现在)。 想法是(在C上,但我想它不是isuue):给定一个长度为n的字符*,您应该使用O(1)内存comp(就地更改),并将相同字符的模式压缩为“num+char”,其中num是模式长度,char是模式的字符。您可以假设内存足够长,可以包含预期的结果。预期时间补偿为O(n) 示例-[abbbcccdee]-->[1a3b4c1d2e] 我在这里的主要问题是关于1长模式的情况,因为“向前推”所有字母以得到前面的1,增加了复杂性。否则,我的想法是使用一个指针来指示下一个压缩模式的位置,并且它只在指针位于数组的常规扫描之后时才起作用 谢谢 压缩“相同字母模式” 我在这里的主要问题是关于1长模式的情况,因为“向前推”所有字母以得到前面的1,增加了复杂性 记下第一道工序所需的长度,以保持O(n)并从末端展开Arrays O(n)就地压缩算法;“相同字母模式”;,arrays,c,time-complexity,Arrays,C,Time Complexity,这是我在这里的第一篇文章,所以我希望我能遵守规则。 几天前我参加了一次工作面试,我遇到了一个我能解决的问题(直到现在)。 想法是(在C上,但我想它不是isuue):给定一个长度为n的字符*,您应该使用O(1)内存comp(就地更改),并将相同字符的模式压缩为“num+char”,其中num是模式长度,char是模式的字符。您可以假设内存足够长,可以包含预期的结果。预期时间补偿为O(n) 示例-[abbbcccdee]-->[1a3b4c1d2e] 我在这里的主要问题是关于1长模式的情况,因为“向
2次传球 压缩:
从开始计算字符重复数开始遍历字符串:
--如果遇到数字,则出错。
--将任何重复的2个或更多字符替换为十进制长度,即文本后跟字符。
--计数单个字符的大小写。
请注意压缩数据的长度 展开:
让
source=&s[length]-1
让
destination=&s[长度+单个]-1
从头到尾遍历数组从
源
读取,然后写入目标
:--通过对阵列开始的特殊检测:
----检测缺少前一位数字的字符,然后将其作为“1”+字符写入目标。
----否则,将“数字+字符”复制到目标。按相反顺序复制这些字符,以便使用“12z”,复制“z”,“2”,然后是“1” 保险算法处理
“
案例
近似
压缩“相同字母模式”
我在这里的主要问题是关于1长模式的情况,因为“向前推”所有字母以得到前面的1,增加了复杂性
记下第一道工序所需的长度,以保持O(n)并从末端展开
2次传球 压缩:
从开始计算字符重复数开始遍历字符串:
--如果遇到数字,则出错。
--将任何重复的2个或更多字符替换为十进制长度,即文本后跟字符。
--计数单个字符的大小写。
请注意压缩数据的长度 展开:
让
source=&s[length]-1
让
destination=&s[长度+单个]-1
从头到尾遍历数组从
源
读取,然后写入目标
:--通过对阵列开始的特殊检测:
----检测缺少前一位数字的字符,然后将其作为“1”+字符写入目标。
----否则,将“数字+字符”复制到目标。按相反顺序复制这些字符,以便使用“12z”,复制“z”,“2”,然后是“1” 保险算法处理
“
案例
类似于让我们把@chux惊人的答案变成真实的代码!以下代码:
#include <stdio.h>
#include <assert.h>
#include <ctype.h>
char *compress_num_to_str(char *out, size_t v) {
// the standard output&reverse
char *tmp = out;
while (v) {
*tmp++ = v % 10 + '0';
v /= 10;
}
char *ret = tmp;
while (tmp > out) {
--tmp;
char a = *tmp;
*tmp = *out;
*out = a;
out++;
}
return ret;
}
char *compress(char *string) {
if (*string == '\0') {
return string;
}
// compress
char *in = string;
char *out = string;
size_t single = 0;
for (char c; (c = *in++) != '\0'; ) {
// the letter is going to be written anyway
char *const pos = in;
// iterate over repeated letters
while (c == *in) {
++in;
}
// if there are any repeated letters
if (pos != in) {
// output the count
const size_t count = in - pos + 1;
out = compress_num_to_str(out, count);
} else {
// a single char
single++;
}
*out++ = c;
}
const size_t length = out - string;
// expand
in = &string[length];
out = &string[length + single];
*out = '\0';
// I am not particularly happy at how this loops
// it's unreadable, but hey - it's fast and it works.
char c = *--in; // current character is buffered to be read
int cont; // should _the next_ loop continue
do {
// this should be a letter always
assert(!isdigit(c));
*--out = c;
// put the letter into destination
if ((cont = in != string) && (c = *--in, isdigit(c))) {
// copy up until digits
do {
*--out = c;
} while ((cont = in != string) && (c = *--in, isdigit(c)));
} else {
// the next input is not a digit
// add a one and repeat
*--out = '1';
}
} while (cont);
assert(in == string);
assert(out == string);
return string;
}
#define TEST(str) printf("%s -> %s\n", str, compress((char[sizeof(str) * 2 - 1]){str}))
int main() {
TEST("abbcccddddeef");
TEST("aabcdee");
TEST("");
TEST("a");
TEST("abcde");
TEST("aaaaaaaaaaaaaaaaaab");
TEST("aaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
TEST("abbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
}
让我们把@chux惊人的答案变成真实的代码!以下代码:
#include <stdio.h>
#include <assert.h>
#include <ctype.h>
char *compress_num_to_str(char *out, size_t v) {
// the standard output&reverse
char *tmp = out;
while (v) {
*tmp++ = v % 10 + '0';
v /= 10;
}
char *ret = tmp;
while (tmp > out) {
--tmp;
char a = *tmp;
*tmp = *out;
*out = a;
out++;
}
return ret;
}
char *compress(char *string) {
if (*string == '\0') {
return string;
}
// compress
char *in = string;
char *out = string;
size_t single = 0;
for (char c; (c = *in++) != '\0'; ) {
// the letter is going to be written anyway
char *const pos = in;
// iterate over repeated letters
while (c == *in) {
++in;
}
// if there are any repeated letters
if (pos != in) {
// output the count
const size_t count = in - pos + 1;
out = compress_num_to_str(out, count);
} else {
// a single char
single++;
}
*out++ = c;
}
const size_t length = out - string;
// expand
in = &string[length];
out = &string[length + single];
*out = '\0';
// I am not particularly happy at how this loops
// it's unreadable, but hey - it's fast and it works.
char c = *--in; // current character is buffered to be read
int cont; // should _the next_ loop continue
do {
// this should be a letter always
assert(!isdigit(c));
*--out = c;
// put the letter into destination
if ((cont = in != string) && (c = *--in, isdigit(c))) {
// copy up until digits
do {
*--out = c;
} while ((cont = in != string) && (c = *--in, isdigit(c)));
} else {
// the next input is not a digit
// add a one and repeat
*--out = '1';
}
} while (cont);
assert(in == string);
assert(out == string);
return string;
}
#define TEST(str) printf("%s -> %s\n", str, compress((char[sizeof(str) * 2 - 1]){str}))
int main() {
TEST("abbcccddddeef");
TEST("aabcdee");
TEST("");
TEST("a");
TEST("abcde");
TEST("aaaaaaaaaaaaaaaaaab");
TEST("aaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
TEST("abbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
}
两个指针。一个用于阅读,一个用于写作。谢谢你的回复,我会澄清,我的问题是写指针在读指针之前的情况,这样它会超过我还没有扫描过的字符。顺便说一句,你描述一下。如果我们加上字母不包括数字的限制,这可以通过三个过程完成:首先压缩非1个字母的运行,扫描以找到最终长度,从末尾开始扩展1个字母的运行。有时,
char buffer[256]是不明显的
实际上是O(1),与O(256)相同。拥有一个足以提前数步的缓冲区似乎是一个很大的帮助。更好的是,int频率[256]
也是O(1),它允许我们以O(n)为单位预计算输出缓冲区大小,然后与O(n)相加以计算输出字符串,并给出另一个O(n)…两个指针。一个用于阅读,一个用于写作。谢谢你的回复,我会澄清,我的问题是写指针在读指针之前的情况,这样它会超过我还没有扫描过的字符。顺便说一句,你描述一下。如果我们加上字母不包括数字的限制,这可以通过三个过程完成:首先压缩非1个字母的运行,扫描以找到最终长度,从末尾开始扩展1个字母的运行。有时,char buffer[256]是不明显的
实际上是O(1),与O(256)相同。拥有一个足以提前数步的缓冲区似乎是一个很大的帮助。更好的是,int频率[256]
也是O(1),它允许我们以O(n)为单位预计算输出缓冲区大小,然后与O(n)相加以计算输出字符串,并给出另一个O(n)。。。