前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >KMP算法

KMP算法

作者头像
xiaohejun
发布于 2020-02-18 01:30:44
发布于 2020-02-18 01:30:44
54100
代码可运行
举报
运行总次数:0
代码可运行

前述:

以下讨论字符串下标均从0开始

解决的问题:

一个文本串$S$(主串)和一个模式串$P$,求$P$在$S$中出现的位置,或者$P$在$S$中出现的次数,等等问题。

暴力做法:

复杂度是$O(n*m)$,$n$是$P$的长度,$m$是$S$的长度

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
#define dbg(x) cout << #x"=" << x << endl;
const int MAX_N = 1e3+100;
char s[MAX_N], p[MAX_N];

// 返回P在S中的出现次数
int solve(char P[], int n, char S[], int m){
    int ans = 0;
    int i,j;
    for(i = 0; i+n <= m; ++i){
        for(j = 0; j < n; ++j){
            if(S[i+j] != P[j]){
                break;  
            }
        }
        if(j == n) {
            ans++;
        }
    }
    return ans;
}

int main(){
   // freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(0); cin.tie(0);
    cin >> s >> p;
    dbg(solve(p, strlen(p), s, strlen(s)))
    return 0;
}

讨论:

暴力做法,字符失配以后,模式串往后移动一步,重新开始匹配

S: ABCDABCDABDE

P: ABCDABD

此时在$i=6$且$j=6$处失配($i$表示指向$S$的下标,$j$表示指向$P$的下标),由于失配,按照暴力做法,下一步的比较是下面这样的:

S: ABCDABCDABDE

P: ABCDABD

此时$i=1$,$j=0$重新开始比较

KMP的做法:发生不匹配的时候,$i$不移动,直接移动模式串的位置,也就是$j$的位置,假设新的$j$的位置是$k(k < j)$,那么要求尽可能大的$k$使得:

$S[i-k…i-1]=P[0…k-1]$(式子1)

失配的前提条件是:

$S[i-j…i-1] = P[0…j-1]$,并且$S[i] != P[j]$(式子2),

由于$k < j$,由式子2可得:

$S[i-k…i-1] = P[j-k…j-1]$(式子3)

那么由式子1和式子3可得$P[0…k-1]=P[j-k…j-1]$

下面用文字的方式来解释:

式子2表示$P$的长度是$j$的前缀等于$S$的长度是$i$的前缀的长度是$j$的后缀,然后此时$S[i] != P[j]$,也就是失配了,我们知道了前面相等的匹配信息,所以不能浪费这些信息。

式子1表示我们不动下标$i$,只动下标$j$,然后使得$P$的长度是$k$的前缀等于$S$的长度是$i$的前缀的长度是$k$的后缀。然后$k < j$并且$k$越大越好。

由式子2我们推出式子3,也就是$P$的长度是$j$的前缀的长度是$k$的后缀等于$S$的长度是$i$的前缀的长度是$k$的后缀。

根据上面的叙述,我们定义一个数组$next$:

$next[j] = k$,表示到$S[i] != P[j]$的时候,下一步$j$指针需要跳到$k$的位置

由上面的分析可以知道。$next[j]=k$表示为满足$P[0…k-1] = P[j-k…j-1]$的最大$k$

文字解释:

$next[j]$表示字符串$P$的长度是$j$的前缀的前缀和后缀相等的最大长度

P:ABCDABD

next:-1 0 0 0 0 1 2 0

如何求解next数组:

求解$next$数组的代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void kmp_pre(char P[], int m, int nxt[]){
    int i = 0, j = nxt[0] = -1;
    while(i < m){
        while(j != -1 && P[i] != P[j]) j = nxt[j];
        nxt[++i] = ++j;
    }
}

当前我们已经知道$next[i] = j$,那么可知$P[0…j-1]=P[i-j…i-1]$,如果$P[i] == P[j]$,那么就是$P[0…j]=P[i-j…i]$,那么可以推知$next[i+1]=next[j+1]$,等价于$next[++i]=next[++j]$,如果$P[i] != P[j]$那么令$j=next[j]$,我们已经知道$P[0…next[j]-1]=P[i-next[j]…i-1]$,同样的道理,这样继续下去。可以看出$next$数组是字符串$P$自己和自己匹配的结果。

next数组的其他操作:

1.next数组的跳转:

沿着next数组一直往前,得到的是所有即使前缀也是后缀的字符串

next数组往前跳的步数的步长是一样的,除了最后一次

下标

0

1

2

3

4

5

6

7

8

9

10

11

P

A

B

C

A

B

C

A

B

C

A

B

next

-1

0

0

0

1

2

3

4

5

6

7

8

从11开始跳:

得到11,8,5,2,0

从10开始跳:

得到10,7,4,1,0

从9开始跳:

得到9,6,3,0

从8开始跳:

得到8,5,2,0

等等。。。可以看出步长都是3

从11开始跳到8得到字符串AB

从8跳到5得到字符串ABCAB

从5跳到2得到字符串ABCABCAB

从2跳到0得到字符串ABCABCABCAB

以上四个字符串就是字符串$P$的既是前缀也是后缀的字符串

2.周期性字符串

如果$n \mod (n-next[n]) == 0$,那么循环节的长度是$n-next[n]$

推导一下: 对于模式串$P$有它的前缀$P[0…next[n]-1]$有$P[0…next[n]-1]=P[n-next[n]…n-1]$,通俗的说就是对于串$P[0…n-1]$,它的前半段长度是$k$的串和它的后半段长度是$k$的串相等。那么$n-next[n]$长的字符串就是后面的$P[n-(n-next[n])…n-1]$,也就是$P[next[n]…n-1]$,假设现在条件成立,即$n \mod (n-next[n]) == 0$,对于$next[next[n]]$,有$P[0…next[next[n]]-1]=P[next[n]-next[next[n]]…next[n]-1]$

综上可以推出:$P[next[next[n]]…next[n]-1] = P[next[n]…n-1]$

同样的道理推下去就可以知道循环节的长度是$n-next[n]$

举个例子:

下标

0

1

2

3

4

5

6

7

8

9

10

11

12

P

a

b

c

a

b

c

a

b

c

a

b

c

next

-1

0

0

0

1

2

3

4

5

6

7

8

9

条件:

条件1:

(abcabcabc) abc

abc (abcabcabc)

$P[0…next[n]-1]=P[n-next[n]…n-1]$

条件2:

(abcabc) abcabc

abc (abcabc) abc

$P[0…next[next[n]]-1]=P[next[n]-next[next[n]]…next[n]-1]$

推出结论:

(abcabc) [abc] abc

abc (abcabc) [abc]

$P[next[next[n]]…next[n]-1] = P[next[n]…n-1]$

相关题目练习:

1.POJ3461

题目描述:

给$t$组数据,每一组数据给两个字符串$W$和$T$,求字符串$W$在字符串$T$的出现次数

题解:

直接上kmp就完事了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <string>
#include <iostream>
using namespace std;

typedef long long LL;
#define dbg(x) cout << #x"=" << x << endl;
int t;
string W, T;
int m,n;
const int MAX_M = 1e4+100;
int nxt[MAX_M];

void solve(){
    m = W.size();
    int i,j;
    j = nxt[0] = -1;
    i = 0;
    while(i < m){
        while(j != -1 && W[i] != W[j]) j = nxt[j];
        nxt[++i] = ++j;
    }
    int ans = 0;
    n = T.size();
    for(i = 0, j = 0; i < n; ++i){
        if(j < m && W[j] == T[i]){
            ++j;
        } else {
            while(j > 0){
                j = nxt[j];
                if(W[j] == T[i]){
                    ++j;
                    break;
                }
            }
        }
        if(j == m) ++ans;
    }
    cout << ans << endl;
}

int main(){
    //freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(0); cin.tie(0);
    cin >> t;
    while(t--){
        cin >> W >> T;
        solve();
    }
    return 0;
}

2.hdu1711

题目描述:

有两个序列一个是长度为$n$的数字序列$a$,一个是长度是$m$的数字序列$b$,求最小的$k$使得$a[k…k+m-1] = b[1…m]$

题解:

就是求$b$在$a$中第一次出现的位置,直接上kmp就完事了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
#define dbg(x) cout << #x"=" << x << endl;
const int MAX_N = 1e6+100;
const int MAX_M = 1e4+100;
int a[MAX_N], b[MAX_M];
int nxt[MAX_M];
int n,m;
int T;

void solve(){
    cin >> n >> m;
    for(int i = 0; i < n; ++i) cin >> a[i];
    for(int i = 0; i < m; ++i) cin >> b[i];
    int i = 0, j = nxt[0] = -1;
    while(i < m){
        while(j != -1 && b[i] != b[j]) j = nxt[j];
        nxt[++i] = ++j;
    }
    for(i = 0, j = 0; i < n; ++i){
        if(j < m && a[i] == b[j]){
            ++j;
        } else {
            while(j > 0){
                j = nxt[j];
                if(a[i] == b[j]){
                    ++j;
                    break;
                }
            }
        }
        if(j == m) {
            cout << i-m+2 << endl; 
            return;
        }
    }
    cout << "-1" << endl;
}

int main(){
    //freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(0); cin.tie(0);
    cin >> T;
    while(T--) solve();
    return 0;
}

/*
a[k...k+m-1] = b[1...m]

*/

3.poj1961

题目描述:

求一个字符串的前缀中的周期性字符串个数

题解:

利用$next$数组的性质求解

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>
#include <string>
using namespace std;

typedef long long LL;
#define dbg(x) cout << #x"=" << x << endl;
const int MAX_N = 1e6+100;
int nxt[MAX_N];
int n;
string s;

void solve(int t){
    cin >> s;
    int i = 0, j = nxt[0] = -1;
    while(i < n){
        while(j != -1 && s[i] != s[j]) j = nxt[j];
        nxt[++i] = ++j;
    }
    cout << "Test case #" << t << endl;
    for(int i = 2; i <= n; ++i){
        if(i%(i-nxt[i]) == 0){
            int k = i/(i-nxt[i]);
            if(k > 1) cout << i << " " << k << endl;
        }
    }
    cout << endl;
}
 
int main(){
    //freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(0); cin.tie(0);
    int t = 0;
    while(cin >> n && n) {
        solve(++t);
    }
    return 0;
}

4.poj2406

题目描述:

求一个字符串由几个周期性字符串构成

题解:

解法大致同上一题

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;

typedef long long LL;
#define dbg(x) cout << #x"=" << x << endl;
const int MAX_N = 1e6+100;
char s[MAX_N];
int nxt[MAX_N];
 
int main(){
    //freopen("in.txt", "r", stdin);
    while(~scanf("%s", s) && s[0] != '.'){
        int i = 0, j = nxt[0] = -1;
        int n = strlen(s);
        while(i < n){
            while(j != -1 && s[i] != s[j]) j = nxt[j];
            nxt[++i] = ++j;
        }
        printf("%d\n",  n%(n-nxt[n]) ? 1 : n/(n-nxt[n]));
    }
    return 0;
}

5.hdu3336

题目描述:

求一个字符串中前缀在该字符串中出现的次数总和

题解:

解法1:

$dp[i]$ 表示长度是$i$的前缀的出现次数

$nxt[i]$表示前缀是$i$的字符串的前缀和后缀相等的最大长度

也就是说只要是长度为$i$的前缀在字符串中出现

容易知道$dp[i]$的初始值均为1

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
#define dbg(x) cout << #x"=" << x << endl;
const int MAX_N = 2e5+100;
const int MOD = 10007;
int T;
int n;
char s[MAX_N];
int nxt[MAX_N];
int dp[MAX_N];

void solve(){
    int i = 0, j = nxt[0] = -1;
    while(i < n){
        while(j != -1 && s[i] != s[j]) j = nxt[j];
        nxt[++i] = ++j;
    }
    int ans = 0;
    for(int i = 1; i <= n; ++i) dp[i] = 1;
    for(int i = n; i >= 1; --i){
        dp[nxt[i]] = dp[nxt[i]] + dp[i];
        ans = (ans + dp[i]) % MOD;
    }
    cout << ans << endl;
}

int main(){
    //freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(0); cin.tie(0);
    cin >> T;
    while(T--) {
        cin >> n;
        cin >> s;
        solve();
    }
    return 0;
}

解法2:

$dp[i]$表示前$i$个字符中前缀的匹配次数,显然$dp[0]=0$

动态转移方程$dp[i]=dp[nxt[i]]+1$

也就是说:前$i$个字符中前缀的匹配次数等于前$nxt[i]$中前缀的匹配次数加上1,

加上的1显然就是长度为$i$的前缀

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
#define dbg(x) cout << #x"=" << x << endl;
const int MAX_N = 2e5+100;
const int MOD = 10007;
int T;
int n;
char s[MAX_N];
int nxt[MAX_N];
int dp[MAX_N];

void solve(){
    int i = 0, j = nxt[0] = -1;
    while(i < n){
        while(j != -1 && s[i] != s[j]) j = nxt[j];
        nxt[++i] = ++j;
    }
    int ans = 0;
    dp[0] = 0;
    for(int i = 1; i <= n; ++i){
        dp[i] = dp[nxt[i]] + 1;
        ans = (ans + dp[i]) % MOD;
    }
    cout << ans << endl;
}

int main(){
//    freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(0); cin.tie(0);
    cin >> T;
    while(T--) {
        cin >> n;
        cin >> s;
        solve();
    }
    return 0;
}

6.hdu3746

题目描述:

求最少在一个字符串后面条件多少个字符使得该字符串是一个周期性字符串

题解:

由next数组的周期性可以知道。令$rem = n - next[n]$,可以知道当前字符串被分成若干段长度是$rem$的字符串,但是最后一段长度不一定是$rem$,所以只要看模数是多少,补齐使得对$rem$取余是0就行了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
#define dbg(x) cout << #x"=" << x << endl;
const int MAX_N = 1e5+100;
int T;
char s[MAX_N];
int nxt[MAX_N];

void solve(){
    int i = 0, j = nxt[0] = -1;
    int n = strlen(s);
    while(i < n){
        while(j != -1 && s[i] != s[j]) j = nxt[j];
        nxt[++i] = ++j;
    }
    int rem = n-nxt[n];
    int mod = n%rem;
    if(nxt[n] == 0) cout << n << endl;
    else cout << (rem-mod) % rem << endl;
}

int main(){
    //freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(0); cin.tie(0);
    cin >> T;
    while(T--) {
        cin >> s;
        solve();
    }
    return 0;
}

7.hdu2594

题目描述:

求$s1$的前缀和$s2$的后缀的最大匹配

题解:

下面的做法是错误的,但是交上去还是对了,数据弱得一皮,过不了下面这一组数据

xxoooxxxxxxxxx ooo

将$s1$和$s2$拼接成为$s$,求$s$的$nxt$数组。如果$nxt[n]==0$那么答案就是0这个显而易见。如果$nxt[n] <= min(|s1|, |s2|)$,那么答案长度就是$nxt[n]$,(错误分析开始)如果$nxt[n] > min(|s1|,|s2|)$,那么长度取$min(|s1|, |s2|)$

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
#define dbg(x) cout << #x"=" << x << endl;
const int MAX_N = 1e5+100;
string s1, s2;
int nxt[MAX_N];

int main(){
   // freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(0); cin.tie(0);
    while(cin >> s1 >> s2){
        int x = s1.size();
        int y = s2.size();
        string s = s1+s2;
        int n = s.size();
        int i = 0, j = nxt[0] = -1;
        while(i < n){
            while(j != -1 && s[i] != s[j]) j = nxt[j];
            nxt[++i] = ++j;
        }
        if(nxt[n]) {
            int len = min(min(x, y), nxt[n]);
            cout << s.substr(0, len) << " " << len << endl;
        } else cout << "0" << endl;
    }
    return 0;
}

正确做法:

将$s1$和$s2$连接成$s$,求$s$的$next$数组,从$n$开始跳,直到跳到某个$j$使得$next[j] <= mn(|s1|, |s2|)$。这个其实用到了$next$数组的那个周期性的性质。每次跳的步数是$n-next[n]$,也就是说每次不要的字符串长度是$n-next[n]$这么长,最后得到的字符串长度$<=min(|s1|, |s2|)$而且相等。kmp的$next$数组简直就是米奇妙妙屋

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
#define dbg(x) cout << #x"=" << x << endl;
const int MAX_N = 1e5+100;
string s1, s2;
int nxt[MAX_N];

int main(){
    //freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(0); cin.tie(0);
    while(cin >> s1 >> s2){
        int x = s1.size();
        int y = s2.size();
        int mn = min(x, y);
        string s = s1+s2;
        int n = s.size();
        int i = 0, j = nxt[0] = -1;
        while(i < n){
            while(j != -1 && s[i] != s[j]) j = nxt[j];
            nxt[++i] = ++j;
        }
        int len = nxt[n];
        j = n;
        while(len > mn){ // nxt[j] <= mn
            j = nxt[j];
            len = nxt[j];
        }
        if(len) cout << s.substr(0, len) << " " << len << endl;
        else cout << "0" << endl;
    }
    return 0;
}
/*
(xxooo)xxxxxxx(xxooo)

*/

8.poj2185

题目描述:

给一个字符串矩阵,求一个最小的矩阵使得把这个矩阵循环重复铺开之后它的一个子矩阵是给的那个矩阵

题解:

按行看,把每一行当一个字母,得到一个字符串,求这个字符串的$next$数组,则答案矩阵的$r = R - nxt[R]$,同样道理按列看,求得$c = C - nxt[C]$,答案为$r * c$。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>
#include <string>

using namespace std;

typedef long long LL;
#define dbg(x) cout << #x"=" << x << endl;
const int MAX_R = 1e4+100;
const int MAX_C = 100;
int nxt[MAX_R];
int R,C;
string s[MAX_R];
string t[MAX_C];

int main(){
    //freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(0); cin.tie(0);
    cin >> R >> C;
    for(int i = 0; i < R; ++i){
        cin >> s[i]; 
    }
    int i = 0, j = nxt[0] = -1;
    while(i < R){
        while(j != -1 && s[i] != s[j]) j = nxt[j];
        nxt[++i] = ++j;
    }
    int r = R - nxt[R];
    for(int j = 0; j < C; ++j){
        t[j] = "";
        for(int i = 0; i < R; ++i){
            t[j] += s[i][j];
        }
    }
    i = 0, j = nxt[0] = -1;
    while(i < C){
        while(j != -1 && t[i] != t[j]) j = nxt[j];
        nxt[++i] = ++j;
    }
    int c = C - nxt[C];
    cout << r * c << endl;
    return 0;
}

9.hdu4763

题目描述:

在一个字符串$s$中求一个子串$t$,使得$t$在$s$的前,中,后位置都有匹配。

题解:

根据$next$数组的含义,$next[i]$表示字符串$s$的长度是$i$的前缀中的相等的最长前缀和后缀。所以答案就是$min(next[n], max(next[1…n-1]))$。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
#define dbg(x) cout << #x"=" << x << endl;
const int MAX_N = 1e6+100;
char s[MAX_N];
int nxt[MAX_N];
int T;

int main(){
   // freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(0); cin.tie(0);
    cin >> T;
    while(T--){
        cin >> s;
        int n = strlen(s);
        int i = 0, j = nxt[0] = -1;
        while(i < n){
            while(j != -1 && s[i] != s[j]) j = nxt[j];
            nxt[++i] = ++j;
        }
        int mx = nxt[1];
        for(int i = 2; i <= n-1; ++i) mx = max(mx, nxt[i]);
        cout << min(mx, nxt[n]) << endl;
    }
    return 0;
}

10.hdu6153

题目描述:

有两个字符串$s1$和$s2$,令$s2$的某一个后缀的权值是长度乘上该后缀在$s1$中的出现次数,求$s2$的所有后缀的权值和对$1e9+7$取模的值

题解:

首先想办法求$s2$中某一个后缀在$s1$中的出现次数。将$s1$和$s2$都逆序,问题就转换横求$s2$中的某一个前缀在$s1$中出现的次数。和hdu3336类似,hdu3336求的是

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
#define dbg(x) cout << #x"=" << x << endl;
const int MAX_N = 1e6+100;
const LL MOD = 1e9+7;
int nxt[MAX_N];
LL dp[MAX_N];
LL N[MAX_N];
char s1[MAX_N], s2[MAX_N];
int T;

void solve(){
    cin >> s1 >> s2;
    int n = strlen(s1), m = strlen(s2);
    reverse(s1, s1+n);
    reverse(s2, s2+m);
    for(int i = 0; i <= m; ++i) dp[i] = 0;
    int i = 0, j = nxt[0] = -1;
    while(i < m){
        while(j != -1 && s2[i] != s2[j]) j = nxt[j];
        nxt[++i] = ++j;
    }
    for(i = 0, j = 0; i < n; ++i){
        if(j < m && s1[i] == s2[j]){
            dp[++j]++;
        } else {
            while(j > 0){
                j = nxt[j];
                if(s1[i] == s2[j]){
                    dp[++j]++;
                    break;
                }
            }
        }
    }
    for(i = m; i >= 1; --i){
        dp[nxt[i]] += dp[i];
    }
    LL ans = 0;
    for(i = 1; i <= m; ++i){
        ans = (ans + i * dp[i] % MOD) % MOD;
    }
    cout << ans << endl;
}

int main(){
   // freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(0); cin.tie(0);
    cin >> T;
    while(T--) solve();
    return 0;
}

11.hdu5510

题目描述:
题解:
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-01-232,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
C# 实时折线图,波形图
此Demo是采用VS自带的Chart图表控件,制作实时动态显示的折线图,和波形图。本文仅供学习分享使用,如有不足之处,还请指正。
zls365
2020/08/19
4.4K1
C# 实时折线图,波形图
c#做四则运算小程序
如果,此时的你,依旧没有开学; 恰巧可能还要辅导作业, 然后都是些小学生, 那么可以的话,你就试着做一个小程序。 以下用c#做的一个窗体程序,内容简单,功能凑合 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threa
全栈程序员站长
2021/12/23
7820
c#做四则运算小程序
C# WinForm 界面控件
1.首先插入新的子窗体form1,并设置IsMdiContainer = True 属性。
王 瑞
2022/12/28
3.3K0
C# WinForm 界面控件
C# 加减乘除计算器
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/weixin_42449444/article/details/89391309 写在前面: 前段时间微软在全球最大的同性交友网站GitHub上开源了微软计算器的C++代码:https://github.com/Microsoft/calculator。我在动手做这个计算器之前和大多数人都有着一样的观点:不就是一个计算器
喜欢ctrl的cxk
2019/11/07
1.4K0
使用C#开发第一个应用程序
在做单片机开发的时候,我们有时候会用到上位机。上位机就是PC上的一个应用程序,通过这个应用程序,我们可以显示一些来自下位机(如单片机)的数据,可以通过上位机来控制我们的下位机。由于上位机是做成图形化界面的,方便用户使用,所以,做单片机开发也需要掌握上位机的开发。比如我们常用的串口调试助手就是一个简单的上位机。
飞哥
2020/07/10
1.3K0
使用C#开发第一个应用程序
C# DateTimePicker:日期时间控件「建议收藏」
日期时间控件(DateTimePicker)在时间控件中的应用最多,主要用于在界面上显示当前的时间。
全栈程序员站长
2022/08/31
5.5K0
C# DateTimePicker:日期时间控件「建议收藏」
串口助手(简洁版)上位机软件零基础教程( C# + visual studio2017 )(二)
在上篇博客中,我们完成了串口助手(简洁版)可视化窗体的设计,并且单击启动后可以运行。但是光有外壳,没有灵魂。所以接下来我们将继续一步一步来编写上位机软件的程序部分。
全栈程序员站长
2022/09/03
4K0
串口助手(简洁版)上位机软件零基础教程( C# + visual studio2017 )(二)
winform中使用委托进行窗体之间的传值
一、传统的方式 创建一个公共数据资源类,用于存储窗体2的TextBox的值: public class ComValue { public static string Txtvalue { get; set; } } 窗体1的代码: private void button1_Click(object sender, EventArgs e) { Form2 f2 = new Form2();
指尖改变世界
2018/08/31
2.2K0
winform中使用委托进行窗体之间的传值
电气工程师要了解的上位机知识,C#简单几行代码就能实现Modbus通信,源代码分享
之前一直想用C#写一个MODBUS通信的案例,本来想用SerialPort直接写的,然后发现可以用 nModbus类库,使用nModbus库来编写Modbus通信的C#案例是一个很好的选择,因为它大大简化了Modbus通信的实现过程。
自动化大师
2024/08/14
4370
电气工程师要了解的上位机知识,C#简单几行代码就能实现Modbus通信,源代码分享
五分钟自制计算器
我们在生活中,或多或少都使用过计算器。那么我们是否可以自己制作一款计算器呢,答案当然是可以的。这里我介绍一款通过C#编写的计算机,大家可以用来借鉴。
跋扈洋
2021/04/08
1.3K0
c#实时显示时间 C#-WinForm-Timer控件
=======================================================
vv彭
2020/10/27
3.7K0
c#实时显示时间
    


C#-WinForm-Timer控件
C# 答群友:把窗体应用改成类库输出然后去引用
类库你就新建类库文件直接生成dll去引用好了,但是群友非要骚操作,新建一个windows窗体把他搞成dll去引用,当时我回答了这个问题是可以的,但是实际上我没有这么干过,今天恰好有空,体验了一把,的确可以。
用户9127601
2021/11/01
2920
C# 生成事件log
在 WindowsFormsApp31.Form1.test1() 位置 C:\Users\lin\source\repos\WindowsFormsApp31\WindowsFormsApp31\Form1.cs:行号 58
zls365
2020/08/19
5240
C# 生成事件log
C#-窗体之自制闹钟
来吧展示闹钟 放桌面上定个小闹钟提醒自己 时间到了就放一曲我最喜欢的夜曲 设置时间闹钟响了 展示源码: public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void timer1_Tick(object sender, EventArgs e) {
用户9857551
2022/06/28
1.5K0
C#-窗体之自制闹钟
3-1 Fileinfo类的常用方法
本案例将解决,同磁盘环境下文件复制的问题。请尝试把C:\WinNT\Win.INI文件拷贝到C:\下的代码,怎么写呢?
py3study
2020/01/06
8610
C# 获取txt文件邮箱号码并去重复
这是咱们C# 开发交流群里好友昨天提的问题: 主要是从txt文件中删除重复的邮箱号 以下是实现的代码: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windo
zls365
2020/08/19
1K0
C# 获取txt文件邮箱号码并去重复
【愚公系列】2023年11月 Winform控件专题 Timer控件详解
Winform控件是Windows Forms中的用户界面元素,它们可以用于创建Windows应用程序的各种视觉和交互组件,例如按钮、标签、文本框、下拉列表框、复选框、单选框、进度条等。开发人员可以使用Winform控件来构建用户界面并响应用户的操作行为,从而创建功能强大的桌面应用程序。
愚公搬代码
2023/11/30
1K0
C#贪吃蛇游戏(全代码)
这是本人第一篇博客,感谢收看,之后对游戏做出的修改,将以方法代码块放在最后
全栈程序员站长
2022/08/31
1.8K0
C# 代码分两个窗体编写
form1: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApp4 {
zls365
2020/08/19
4630
C# 代码分两个窗体编写
C# Timer控件学习之使用Timer解决按钮幂等性问题案例分享
代码比较简单,我们重在学习,学一下这个控件证明用,知道逻辑就可以了,代码很简单,两个按钮两个定时器,将它们的触发函数看懂就可以实现了,按钮一的操作就是针对按钮重复提交而设计的。
用户7718188
2022/11/06
8760
相关推荐
C# 实时折线图,波形图
更多 >
LV.2
物联网嵌入式
目录
  • 前述:
  • 解决的问题:
  • 暴力做法:
  • 讨论:
  • 如何求解next数组:
  • next数组的其他操作:
    • 1.next数组的跳转:
    • 2.周期性字符串
  • 相关题目练习:
    • 1.POJ3461
      • 题目描述:
      • 题解:
    • 2.hdu1711
      • 题目描述:
      • 题解:
    • 3.poj1961
      • 题目描述:
      • 题解:
    • 4.poj2406
      • 题目描述:
      • 题解:
    • 5.hdu3336
      • 题目描述:
      • 题解:
    • 6.hdu3746
      • 题目描述:
      • 题解:
    • 7.hdu2594
      • 题目描述:
      • 题解:
    • 8.poj2185
      • 题目描述:
      • 题解:
    • 9.hdu4763
      • 题目描述:
      • 题解:
    • 10.hdu6153
      • 题目描述:
      • 题解:
    • 11.hdu5510
      • 题目描述:
      • 题解:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档