Sau khi xem lại, nó hiện thực hơi khác, không phải là đếm chiều dài dãy con chung dài nhất.
Nó liệt kê tất cả dãy con chung dài nhất, dài nhì, dài ba,… Mỗi dãy có chiều lần lượt l1, l2, l3,…
Kết quả trả về: l1 + l2 + l3 + …
Cách liệt kê hơi bị quái dị, mình viết lại mã giả như sau, giả sử input là $str1 và $str2:
-
Khởi tạo: biến sum
đếm tổng số dãy con chung có độ dài lớn nhất, giá trị 0.
-
Bước 1: Tìm dãy con chung dài nhất, nếu có nhiều dãy con có cùng độ dài lớn nhất thì chọn dãy nằm bên trái. Biến sum
được cộng thêm chiều dài của dãy chung được chọn.
- Nằm bên trái là có dãy chung có index trong $str1 nhỏ nhất. Nếu có nhiều dãy chung có giá trị index trong $str1 bằng nhau thì lấy dãy chung có index trong $str2 nhỏ nhất.
-
Bước 2: Cắt 2 chuỗi từ đầu chuỗi đến cuối đoạn dãy chung, thực hiện bước 1 cho 2 chuỗi mới.
Viết có vẻ khó hiểu (mình đọc cũng chả hiểu
), nên làm ví dụ cho dễ hiểu:
012345678901
-----------------------
$str1 = 'PHP IS GREAT';
$str2 = 'WITH MYSQL';
Bước 1:
Sau khi mò các kiểu, chỉ thấy dãy chung của $str1 và $str2 có độ dài lớn nhất là 1: (’ ’ là space)
|
$str1 |
$str2 |
‘H’ |
1 |
3 |
’ ’ |
3 |
4 |
’ ’ |
6 |
4 |
‘S’ |
5 |
7 |
‘T’ |
11 |
2 |
Trong 5 dãy trên, chỉ dãy ‘H’ có index $str1 là nhỏ nhất nên được chọn là dãy chung.
sum = sumold + 1 = 0 + 1 = 1
Bước 2:
Cắt chuỗi $str1. ([…] là dãy chung, | là chỗ cắt chuỗi)
'PHP IS GREAT' --> 'P[H]|P IS GREAT' --> 'P IS GREAT'
$str1 = 'P IS GREAT';
Cắt chuỗi $str2.
'WITH MYSQL' --> 'WIT[H]| MYSQL' --> ' MYSQL'
$str2 = ' MYSQL'; // có space trước MYSQL
Bước 1:
0123456789
--------------------
$str1 = 'P IS GREAT';
$str2 = ' MYSQL';
Dãy con chung có chiều dài lớn nhất là 1
|
$str1 |
$str2 |
’ ’ |
1 |
0 |
’ ’ |
4 |
0 |
‘S’ |
3 |
3 |
Dãy ’ ’ được chọn vì index $str1 nhỏ nhất, bằng 1
sum = sumold + 1 = 1 + 1 = 2
Bước 2:
Cắt chuỗi $str1
'P IS GREAT' --> 'P[ ]|IS GREAT' --> 'IS GREAT'
$str1 = 'IS GREAT';
Cắt chuỗi $str2
' MYSQL' --> '[ ]|MYSQL' --> 'MYSQL'
$str2 = 'MYSQL';
Bước 1:
01234567
------------------
$str1 = 'IS GREAT';
$str2 = 'MYSQL';
Dãy con chung có chiều dài lớn nhất là 1
Dãy chung ‘S’ có độ dài 1 được chọn.
sum = sumold + 1 = 2 + 1 = 3
Bước 2:
Cắt chuỗi $str1
'IS GREAT' --> 'I[S]| GREAT' --> ' GREAT'
$str1 = ' GREAT';
Cắt chuỗi $str2
'MYSQL' --> 'MY[S]|QL' --> 'QL'
$str2 = 'QL';
Bước 1:
012345
-----------------
$str1 = ' GREAT';
$str2 = 'QL';
Hai dãy trên không có dãy chung.
Kết luận: Trả về giá trị sum
= 3.
Phần sau là code hiện thực, bấm nút mũi tên để xem thêm.
Function php_similar_str()
trả về chuỗi con chung dài nhất.
Input:
- txt1, len1: pointer trỏ tới địa chỉ đầu tiên chuỗi thứ nhất và chiều dài của nó.
- txt2, len2: pointer và chiều dài của chuỗi thứ 2, tương tự như trên.
Output:
- pos1: pointer trỏ đến dãy con chung trong chuỗi đầu tiên.
- pos2: pointer trở đến dãy con chung trong chuỗi thứ hai.
- max: chiều dài của dãy con.
Local variable:
- p, q: pointer hiện tại (current pointer), dùng trong vòng lặp for.
- end1: pointer trỏ đến địa chỉ cuối cùng của chuỗi thứ nhất txt1.
- end2: pointer trỏ đến địa chỉ cuối cùng của chuỗi thứ hai txt2.
- l: chiều dài chuỗi con chung dài nhất (nếu tìm thấy) khi lặp đến p và q.
static void php_similar_str(const char *txt1, int len1, const char *txt2, int len2, int *pos1, int *pos2, int *max)
{
char *p, *q;
char *end1 = (char *) txt1 + len1;
char *end2 = (char *) txt2 + len2;
int l;
*max = 0;
for (p = (char *) txt1; p < end1; p++) { // <-- (1)
for (q = (char *) txt2; q < end2; q++) { // <-- (2)
for (l = 0; (p + l < end1) && (q + l < end2) && (p[l] == q[l]); l++); // <-- (3)
if (l > *max) { // <-- (4)
*max = l;
*pos1 = p - txt1;
*pos2 = q - txt2;
}
}
}
}
Lệnh for
(1) và (2) để duyệt 2 chuỗi, p trên txt1 và q trên txt2.
Lệnh for
(3) tìm chiều dài dãy con chung, tức l.
Lệnh if
(4) kiểm tra dãy con chiều dài l có lớn hơn max
và cập nhật các giá trị output.
Nếu có 2 dãy con có cùng chiều dài max
, thì dãy con nào “nằm trên trái” được chọn. (*)
php_similar_char()
hoạt đống giống như similar_text()
trong PHP, trả về số dãy con chung có chiều dài lớn nhất.
static int php_similar_char(const char *txt1, int len1, const char *txt2, int len2)
{
int sum = -1;
int pos1 = -1, pos2 = -1, max = -1;
php_similar_str(txt1, len1, txt2, len2, &pos1, &pos2, &max); // <-- (1)
if ((sum = max)) {
if (pos1 && pos2) { // <-- (2)
sum += php_similar_char(txt1, pos1, txt2, pos2); // <-- (3)
}
if ((pos1 + max < len1) && (pos2 + max < len2)) {
sum += php_similar_char(txt1 + pos1 + max, len1 - pos1 - max, txt2 + pos2 + max, len2 - pos2 - max); // <-- (4)
}
}
return sum;
}
Bước 1:
Gọi (1) tới php_similar_str()
để tìm chuỗi con chung “nằm bên trái” (từ (*)) dài nhất trong 2 dãy. Nếu có thì cộng vào biến sum
ở (3).
- (3) thực chất thực hiện giống (1). Khi thực thi (1) trong (3), 1 trong 2 giá trị pos1 hoặc pos2 bằng 0, làm cho lệnh if (2) không thực hiện.
Bước 2:
Cắt chuỗi bằng cách thay đổi pointer và length, và gọi đệ quy (4)
- txt1 = txt1 + (pos1 + max)
- len1 = len1 - (pos1 + max)
- txt2 = txt2 + (pos2 + max)
- len2 = len2 - (pos2 + max)
Source code
#include<stdio.h>
static void print_str_index(int len1, int len2) {
int i, len;
len = len1 > len2 ? len1 : len2;
for (i = 0; i < len; i++)
printf("%d", i%10);
printf("\n");
for (i = 0; i < len; i++)
printf("-");
printf("\n");
}
static void print_sub_str(const char *txt, int len)
{
int i;
for (i = 0; i < len; i++)
printf("%c", txt[i]);
printf("\n");
}
/* {{{ php_similar_str
*/
static void php_similar_str(const char *txt1, int len1, const char *txt2, int len2, int *pos1, int *pos2, int *max)
{
char *p, *q;
char *end1 = (char *) txt1 + len1;
char *end2 = (char *) txt2 + len2;
int l;
*max = 0;
for (p = (char *) txt1; p < end1; p++) {
for (q = (char *) txt2; q < end2; q++) {
for (l = 0; (p + l < end1) && (q + l < end2) && (p[l] == q[l]); l++);
if (l > *max) {
*max = l;
*pos1 = p - txt1;
*pos2 = q - txt2;
}
}
}
}
/* }}} */
/* {{{ php_similar_char
*/
static int php_similar_char(const char *txt1, int len1, const char *txt2, int len2, int depth)
{
int sum = -1;
int pos1 = -1, pos2 = -1, max = -1;
php_similar_str(txt1, len1, txt2, len2, &pos1, &pos2, &max);
if ((sum = max)) {
if (pos1 && pos2) {
printf("[%d-1]:\n", depth);
print_str_index(len1, len2);
print_sub_str(txt1, len1);
print_sub_str(txt2, len2);
printf("Pos1: %d, Post2: %d, Max: %d, Sum: %d\n", pos1, pos2, max, sum);
printf("================================\n\n");
sum += php_similar_char(txt1, pos1, txt2, pos2, depth+1);
}
if ((pos1 + max < len1) && (pos2 + max < len2)) {
printf("[%d-2]:\n", depth);
print_str_index(len1, len2);
print_sub_str(txt1, len1);
print_sub_str(txt2, len2);
printf("Pos1: %d, Post2: %d, Max: %d, Sum: %d\n", pos1, pos2, max, sum);
printf("================================\n\n");
sum += php_similar_char(txt1 + pos1 + max, len1 - pos1 - max, txt2 + pos2 + max, len2 - pos2 - max, depth+1);
}
} else {
printf("[%d-3]:\n", depth);
print_str_index(len1, len2);
print_sub_str(txt1, len1);
print_sub_str(txt2, len2);
printf("Pos1: %d, Post2: %d, Max: %d, Sum: %d\n", pos1, pos2, max, sum);
printf("================================\n\n");
}
return sum;
}
/* }}} */
int main(void)
{
printf("Found %d similar chars\n",
php_similar_char("PHP IS GREAT", 12, "WITH MYSQL", 10, 1));
printf("Found %d similar chars\n",
php_similar_char("WITH MYSQL", 10,"PHP IS GREAT", 12, 1));
return 0;
}
Tham khảo: https://stackoverflow.com/questions/14136349/how-does-similar-text-work