Hash

Oulipo

没啥好说的,进制hash板子。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define ull unsigned long long
  4. const int N = 1e6 + 1;
  5. int n, lw, lt, ans;
  6. ull hw, ht[N], p[N];
  7. inline ull gethash(int l, int r){ return ht[r] - ht[l] * p[r - l]; }
  8. inline void wt(int k){ if(k/10) wt(k/10); putchar(k%10+'0'); }
  9. int main(){
  10. p[0] = 1;
  11. for(int i=1; i<=N; ++i) p[i] = p[i-1] * 131;
  12. char ch = getchar();
  13. while(isdigit(ch)) n = (n<<1) + (n<<3) + (ch^48), ch = getchar();
  14. while(n--){
  15. ans = hw = lt = lw = 0;
  16. char ch = getchar();
  17. while(ch < 'A' || ch > 'Z') ch = getchar();
  18. while(ch >= 'A' && ch <= 'Z') hw = hw * p[1] + ch, ++lw, ch = getchar();
  19. while(ch < 'A' || ch > 'Z') ch = getchar();
  20. while(ch >= 'A' && ch <= 'Z' && ++lt){
  21. ht[lt] = ht[lt-1] * p[1] + ch;
  22. ch = getchar();
  23. if(lt >= lw) if(gethash(lt-lw, lt) == hw) ++ans;
  24. } wt(ans), putchar('\n');
  25. } return 0;
  26. }

[USACO17OPEN] Bovine Genomics S

简单来说,存在某一区间使得任意A串与B串都不相等,现在要找这一区间的最小值。进制哈希之后,可以暴力判断某一长度区间是否合法。再加上区间长度和其合法性是有单调关系的(随着区间长度越小,就越不可能合法),所以再加上二分即可

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define ull unsigned long long
  4. int n, m, ans;
  5. ull ha[501][501], hb[501][501], p[501];
  6. string A[501], B[501];
  7. inline void Hash(string str, ull *h){
  8. for(int i=0; i<m; ++i)
  9. h[i+1] = h[i] * p[1] + str[i] - 'A';
  10. }
  11. inline ull gethash(int l, int r, ull *h){ return h[r] - h[l] * p[r-l]; }
  12. inline bool check(int len){ //暴力判断
  13. for(int k=len; k<=m; ++k){
  14. bool data = 0;
  15. for(int i=1; i<=n; ++i)
  16. for(int j=1; j<=n; ++j)
  17. if(gethash(k-len, k, ha[i]) == gethash(k-len, k, hb[j])) data = 1;
  18. if(!data) return 1;
  19. } return 0;
  20. }
  21. int main(){
  22. ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  23. p[0] = 1;
  24. for(int i=1; i<=500; ++i) p[i] = p[i-1] * 131;
  25. cin>>n>>m;
  26. for(int i=1; i<=n; ++i) cin>>A[i], Hash(A[i], ha[i]);
  27. for(int i=1; i<=n; ++i) cin>>B[i], Hash(B[i], hb[i]);
  28. int l = 1, r = m;
  29. while(l < r){
  30. int mid = (l + r) >> 1;
  31. if(check(mid)) r = mid;
  32. else l = mid+1;
  33. } return cout<<l, 0;
  34. }

P4591 [TJOI2018] 碱基序列

hash + 分组背包

dp[i][j] 表示第 \(i\) 组氨基酸放到蛋白质的第 \(j\) 个位置的方案数。同样是每一组只取一种物品放入背包,就可以类比于分组背包。len_z表示第 \(z\) 个氨基酸的长度,于是有转移方程(转移时记得判断是否能配对上):

\[dp[i][j]=\sum\limits_{z=1}^{z=a}dp[i-1][j-len_z]
\]
  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define ull unsigned long long
  4. int n, num[101], ls, lp[101][11], dp[10001], mod = 1e9 + 7, ans;
  5. string s;
  6. ull h[101][11], hs[10001], p[10001];
  7. inline ull gethash(int l, int r){ return hs[r] - hs[l] * p[r-l]; }
  8. int main(){
  9. ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  10. cin>>n>>s;
  11. p[0] = 1; for(int i=1; i<=n; ++i) p[i] = p[i-1] * 131;
  12. ls = s.size();
  13. for(int i=0; i<ls; ++i) hs[i+1] = hs[i] * p[1] + s[i];
  14. for(int i=1; i<=n; ++i){
  15. cin>>num[i];
  16. string str;
  17. for(int j=1; j<=num[i]; ++j){
  18. cin>>str;
  19. lp[i][j] = str.size();
  20. for(int z=0; z<lp[i][j]; ++z) h[i][j] = h[i][j] * p[1] + str[z];
  21. }
  22. }
  23. for(int i=0; i<=ls; ++i) dp[i] = 1; //注意从0开始
  24. for(int i=1; i<=n; ++i)
  25. for(int k=ls; k>=0; --k){//注意要把dp[0]也更新一下
  26. dp[k] = 0;
  27. for(int j=1; j<=num[i]; ++j)
  28. if(k >= lp[i][j] && gethash(k-lp[i][j], k) == h[i][j]) dp[k] = (dp[k] + dp[k - lp[i][j]]) % mod;
  29. if(i == n) ans = (ans + dp[k]) % mod;
  30. } return cout<<ans, 0;
  31. }

[CQOI2014] 通配符匹配

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define ull unsigned long long
  4. #define bl (gethash(j-id[i]+id[i-1], j-1, hp) == gethash(id[i-1], id[i]-1, hs))
  5. const int N = 1e5 + 5;
  6. ull hs[N], p[N], hp[N];
  7. string s, st;
  8. int ls, id[15], n, len, cnt, dp[15][N];
  9. inline ull gethash(int l, int r, ull *h){ return h[r] - h[l] * p[r-l]; }
  10. int main(){
  11. ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  12. p[0] = 1; for(int i=1; i<N; ++i) p[i] = p[i-1] * (ull)131;
  13. cin>>s; s += '?';
  14. ls = s.size();
  15. for(int i=1; i<=ls; ++i){
  16. hs[i] = hs[i-1] * p[1] + s[i-1];
  17. if(s[i-1] == '?' || s[i-1] == '*') id[++cnt] = i;
  18. }
  19. cin>>n;
  20. while(n--){
  21. memset(dp, 0, sizeof dp);
  22. cin>>st; st += 'a';
  23. len = st.size();
  24. for(int i=1; i<=len; ++i) hp[i] = hp[i-1] * p[1] + st[i-1];
  25. dp[0][0] = 1;
  26. for(int i=1; i<=cnt; ++i) for(int j=id[i]-id[i-1]; j<=len; ++j){
  27. if(dp[i][j-1] == 2){ dp[i][j] = 2; continue; }
  28. if(!dp[i-1][j - id[i] + id[i-1]] || !bl) continue;
  29. if(s[id[i]-1] == '?') dp[i][j] = 1;
  30. else dp[i][j] = dp[i][j-1] = 2;
  31. }
  32. if(dp[cnt][len]) cout<<"YES\n";
  33. else cout<<"NO\n";
  34. } return 0;
  35. }

[NOI2017] 蚯蚓排队

上面的内容都只是用hash来映射字符串,但如果要映射数字或者其他数据类型就需要用到哈希表5分钟搞定哈希表。哈希表要比map快的多。

对于本题来说,需要完成以下三个操作:

  1. 合并队伍:这个很好实现,直接用链表模拟即可。用两个数组分别表示某一个蚯蚓的前驱和后继。我们注意到,数据范围中 \(k\) 非常小,不妨考虑暴力统计每一次合并时新产生的字符串。可以将新产生的字符串映射成哈希,接着用哈希表统计该字符串的数量即可。
  2. 分离队伍:同样用链表实现,统计每次分开时消失的字符串,并在哈希表中将数量-1即可。
  3. 统计个数:将字符串 \(s\) 映射成哈希,并在哈希表里统计个数即可。

一般来说,在哈希表中链表越长,搜索效率越差。所以为了提高效率,哈希表开成尽量大的素数。我用的 10000019

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define ull unsigned long long
  4. #define ll long long
  5. const int N = 2e5 + 2, hmod = 10000019, hmax = 1e7 + 5;
  6. const ll mod = 998244353;
  7. int n, m, dt, a, b, nxt[N], lst[N], k;
  8. ull p[N], hs[N], f[N];
  9. string s;
  10. struct Hash_table{
  11. int cnt, head[hmod+1], nxt[hmax]; ull val[hmax]; ll num[hmax];
  12. inline void add(ull h, int v){
  13. int tb = h % hmod;
  14. for(int i=head[tb]; i; i=nxt[i])
  15. if(val[i] == h){ num[i] = num[i] + v; return; }
  16. val[++cnt] = h, ++num[cnt], nxt[cnt] = head[tb], head[tb] = cnt;
  17. }
  18. inline ll query(ull h){
  19. int tb = h % hmod;
  20. for(int i=head[tb]; i; i=nxt[i])
  21. if(val[i] == h) return num[i];
  22. return 0ll;
  23. }
  24. } Hash;
  25. inline int rd(){
  26. int x = 0; char ch = getchar();
  27. while(!isdigit(ch)) ch = getchar();
  28. while(isdigit(ch)) x = (x<<1) + (x<<3) + (ch^48), ch = getchar();
  29. return x;
  30. }
  31. inline string rds(){
  32. string str = ""; char ch = getchar();
  33. while(ch != ' ') str += ch, ch = getchar();
  34. return str;
  35. }
  36. inline void wt(ll k){ if(k/10) wt(k/10); putchar(k%10+'0'); }
  37. inline ull gethash(int l, int r){ return hs[r]-hs[l]*p[r-l]; }
  38. inline void add(int a, int b){
  39. nxt[a] = b, lst[b] = a;
  40. ull nhash = 0, mhash;
  41. for(int i=a, la=1; i&&la<=50; i=lst[i], ++la){
  42. nhash += f[i]*p[la-1], mhash = nhash;
  43. for(int j=b, lb=la+1; j&&lb<=50; j=nxt[j], ++lb){
  44. mhash = mhash * p[1] + f[j];
  45. Hash.add(mhash, 1);
  46. }
  47. }
  48. }
  49. inline void divide(int a){
  50. int b = nxt[a]; ull nhash = 0, mhash;
  51. for(int i=a, la=1; i&&la<=50; i=lst[i], ++la){
  52. nhash += f[i]*p[la-1], mhash = nhash;
  53. for(int j=b, lb=la+1; j&&lb<=50; j=nxt[j], ++lb){
  54. mhash = mhash * p[1] + f[j];
  55. Hash.add(mhash, -1);
  56. }
  57. }
  58. nxt[a] = lst[b] = 0;
  59. }
  60. inline ll query(int k){
  61. int len = s.size(); ll ans = 1;
  62. for(int i=1; i<=len; ++i) hs[i] = hs[i-1]*p[1] + s[i-1] - '0';
  63. for(int i=k; i<=len; ++i){
  64. ull nhash = gethash(i-k, i);
  65. ans = (__int128)ans * Hash.query(nhash) % mod;
  66. } return ans;
  67. }
  68. int main(){
  69. n=rd(), m=rd(); p[0] = 1;
  70. for(int i=1; i<=N; ++i) p[i] = p[i-1] * 131;
  71. for(int i=1; i<=n; ++i) f[i] = rd(), Hash.add(f[i], 1);
  72. while(m-- && (dt=rd())){
  73. if(dt == 1) a=rd(), b=rd(), add(a, b);
  74. if(dt == 2) a=rd(), divide(a);
  75. if(dt == 3) s=rds(), k=rd(), wt(query(k)), putchar('\n');
  76. } return 0;
  77. }

kmp

[POJ 2752] Seek the Name, Seek the Fame

这道题纯纯是考Next数组的。对于一个串来说,它的第一长公共前后缀肯定是他自己,第二就是 \(Next[s.len]\) ,第三就是 \(Next[Next[s.len]]\) 以此类推。在这道题里仅需递推求出所有Next值即可。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N = 4e5 + 1; string s; int Next[N];
  4. inline void getans(int k){
  5. if(!k) return;
  6. getans(Next[k]), cout<<k<<' ';
  7. }
  8. inline void getnext(){
  9. int len = s.size(), j = 0;
  10. Next[0] = Next[1] = 0;
  11. for(int i=1; i < len; ++i, j=Next[i]){
  12. while(j && s[i] != s[j]) j = Next[j];
  13. if(s[i] == s[j]) Next[i+1] = j+1;
  14. else Next[i+1] = 0;
  15. } getans(j), cout<<len<<'\n';
  16. }
  17. int main(){
  18. ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  19. while(cin>>s) getnext(); return 0;
  20. }

[NOI2014] 动物园

这道题是上道题的进阶版本,加深了我对kmp求next数组的思想运用。我们知道,Next[i]是一个字符串里最长前缀后缀的长度,计算num数组其实只需要判断最长前后缀的长度和原字符串的长度即可。思路简单,但问题在于复杂度。这道题的思想和kmp思想是一样的,使用双指针,固定 \(i\) ,活动 \(j\),始终让 \(j\) 保持在 \(i\) 的一半以前,这样复杂度就为 \(O(n)\)。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define ll long long
  4. const int N = 1e7 + 5, mod = 1e9 + 7;
  5. int n, len, Next[N], j, num[N];
  6. string s; ll ans;
  7. inline void getnext(){
  8. Next[0] = Next[1] = 0; j = 0; ans = 1;
  9. for(int i=1; i<len; ++i, j=Next[i]){
  10. num[i] = num[j] + 1;
  11. while(j && s[i] != s[j]) j = Next[j];
  12. Next[i+1] = j + (s[i] == s[j]);
  13. }
  14. num[0] = 0; j = 0;
  15. for(int i=1; i<len; ++i){
  16. while(j && s[i] != s[j]) j = Next[j];
  17. if(s[i] == s[j]) ++j;
  18. while((j<<1) > i+1) j = Next[j];
  19. ans = (__int128)ans * (num[j] + 1) % mod;
  20. }
  21. }
  22. int main(){
  23. ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  24. cin>>n;
  25. while(n--){
  26. cin>>s; len = s.size();
  27. ans = 1; getnext();
  28. cout<<ans<<'\n';
  29. } return 0;
  30. }

[USACO15FEB] Censoring S

算是个kmp板子吧。在板子的基础上,用栈来模拟删除后的字符串,如果可以删除,那就退栈。再建立一个数组存还没匹配完的 \(j\) 的值。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N = 1e6 + 5;
  4. string s, t;
  5. int ls, lt, Next[N], last[N], p[N];
  6. int main(){
  7. ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  8. cin>>s>>t; ls = s.size(), lt = t.size();
  9. for(int i=1, j=0; i<lt; ++i, j=Next[i]){
  10. while(j && t[i] != t[j]) j = Next[j];
  11. Next[i+1] = j + (t[i] == t[j]);
  12. }
  13. for(int i=0, j=0; i<ls; ++i){
  14. while(j && s[i] != t[j]) j = Next[j];
  15. if(s[i] == t[j]) ++j;
  16. last[i] = j;
  17. p[++p[0]] = i;
  18. if(j == lt){
  19. p[0] -= lt;
  20. j = last[p[p[0]]];
  21. }
  22. }
  23. for(int i=1; i<=p[0]; ++i) cout<<s[p[i]];
  24. return 0;
  25. }

[POI2006] OKR-Periods of Words

读完题目后可以发现,其实求的就是字符串 \(S\) 的前缀的最短公共前后缀。所以只需要在求Next数组时添加3行代码即可求出。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N = 1e6 + 5;
  4. int k, Next[N], j, p;
  5. long long ans;
  6. string s;
  7. int main(){
  8. ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  9. cin>>k>>s;
  10. for(int i=1; i<k; ++i, j=Next[i]){
  11. while(j && s[i] != s[j]) j = Next[j];
  12. Next[i+1] = j += (s[i] == s[j]);
  13. p = j;
  14. while(Next[p]) p = Next[p];
  15. if(p) ans += i + 1 - p;
  16. }
  17. return cout<<ans, 0;
  18. }

TLE73。不难发现,当字符串长的时候,会产生许多无用回溯。那么只需要记录下每一个回溯的值,在新的回溯时使用已有的结果,这样就能避免重复回溯。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N = 1e6 + 5;
  4. int k, Next[N], j, p, Last[N];
  5. long long ans;
  6. string s;
  7. int main(){
  8. ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  9. cin>>k>>s;
  10. for(int i=1; i<k; ++i, j=Next[i]){
  11. while(j && s[i] != s[j]) j = Next[j];
  12. Next[i+1] = j += (s[i] == s[j]);
  13. if(Next[j]) Last[j] = Last[Next[j]];
  14. else Last[j] = j;
  15. if(Last[j]) ans += i + 1 - Last[j];
  16. }
  17. return cout<<ans, 0;
  18. }

Trie 树

「POJ 3630」Phone List

Trie树板子。对于静态trie树,数组开多大其实要看运气(能开多大开多大),严格来说tire树空间应该开到 \(26^{26^{26…}}\) 一共有最长字符串长度个26,太大了。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N = 1e6 + 1;
  4. int T, n, cnt;
  5. bool opt;
  6. struct node{
  7. bool repeat, end;
  8. int s[10], num;
  9. }t[N];
  10. string s;
  11. inline void insert(string s){
  12. int len = s.size(), now = 0;
  13. for(int i=0; i<len; ++i){
  14. int ch = s[i] - '0';
  15. if(!t[now].s[ch]) t[now].s[ch] = ++cnt, ++t[now].num;
  16. now = t[now].s[ch];
  17. if(t[now].end) opt = 1;
  18. if(i == len-1){
  19. if(t[now].num) opt = 1;
  20. t[now].end = 1;
  21. }
  22. }
  23. }
  24. int main(){
  25. ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  26. cin>>T;
  27. while(T--){
  28. cin>>n;
  29. memset(t, 0, sizeof t);
  30. opt = 0, cnt = 0;
  31. for(int i=1; i<=n; ++i) cin>>s, insert(s);
  32. if(opt) cout<<"NO\n";
  33. else cout<<"YES\n";
  34. }
  35. }

The XOR Largest Pair

首先,两个数的异或值最大不超过二进制位数最长的那个数的二进制位数,其次需要让其中一个数的取反与另一个数相似。这样就可以保证异或和最大。根据贪心思想,需要从最高位开始搜索,所以在存入字典树时也要从最高位开始存。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N = 1e5 + 1;
  4. int n, mx, cnt, tot, ans, k;
  5. bitset<32> num[N], nump[N];
  6. struct node{ int s[2]; }t[N<<4];
  7. inline void insert(int k){
  8. int now = 0;
  9. for(int i=30; i>=0; --i){
  10. int Bit = num[k][i];
  11. if(!t[now].s[Bit]) t[now].s[Bit] = ++cnt;
  12. now = t[now].s[Bit];
  13. }
  14. }
  15. inline int search(int k, int p){
  16. int now = 0;
  17. for(int i=30; i>=0; --i){
  18. int Bit = !(num[k][i]);
  19. if(t[now].s[Bit]){
  20. now = t[now].s[Bit];
  21. nump[p][i] = 1;
  22. }
  23. else{
  24. if(t[now].s[!Bit]){
  25. now = t[now].s[!Bit];
  26. nump[p][i] = 0;
  27. }else break;
  28. }
  29. } return (int)nump[p].to_ulong();
  30. }
  31. int main(){
  32. ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  33. cin>>n;
  34. for(int i=1; i<=n; ++i){
  35. cin>>k, num[i] = k;
  36. int len = num[i].size();
  37. mx = max(mx, len);
  38. insert(i);
  39. }
  40. for(int i=1; i<=n; ++i){
  41. if(num[i].size() == mx){
  42. nump[++tot] = num[i];
  43. ans = max(ans, search(i, tot));
  44. }
  45. } return cout<<ans, 0;
  46. }

The XOR-longest Path

这道题非常的巧妙。先求出dis[N]的所有值,那么可以知道从 \(1\) 到 \(x\) 的路径为 \(dis(1,x)=dis(1,lca)\oplus dis(lca+1,x)\),那么 \(dis(1,x)\oplus dis(1,y)=dis(1,lca)\oplus dis(1,lca)\oplus dis(lca+1,x)\oplus dis(lca+1,y)=dis(x,y)\)。由此,这道题就和上道题一样了。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define Bit dis[k][i]
  4. const int N = 1e5 + 1;
  5. int n, h[N], cnt, t[N<<4][2], tot, Xor;
  6. bitset<N> vis;
  7. bitset<31> dis[N], ans;
  8. struct edge{ int v, nt; bitset<31> w; }e[N];
  9. inline void add(int u, int v, int w){
  10. e[++cnt].v = v, e[cnt].nt = h[u], e[cnt].w = w; h[u] = cnt;
  11. }
  12. inline void insert(int k){
  13. for(int i=30, now=0; i>=0; --i){
  14. if(!t[now][Bit]) t[now][Bit] = ++tot;
  15. now = t[now][Bit];
  16. }
  17. }
  18. inline void search(int k){
  19. ans = dis[k];
  20. for(int i=30, now=0; i>=0; --i){
  21. if(t[now][!Bit]) ans[i] = 1, now = t[now][!Bit];
  22. else if(t[now][Bit]) ans[i] = 0, now = t[now][Bit];
  23. else break;
  24. }
  25. Xor = max(Xor, (int)ans.to_ulong());
  26. }
  27. inline void dfs(int k){
  28. vis[k] = 1;
  29. insert(k);
  30. search(k);
  31. for(int i=h[k]; i; i=e[i].nt){
  32. int v = e[i].v;
  33. if(vis[v]) continue;
  34. dis[v] = dis[k] ^ e[i].w;
  35. dfs(v);
  36. }
  37. }
  38. int main(){
  39. ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  40. cin>>n;
  41. for(int i=1, a, b, v; i<n; ++i) cin>>a>>b>>v, add(a, b, v);
  42. dfs(1); return cout<<Xor, 0;
  43. }

[学习笔记] hash & kmp & Trie树 - 字符串的更多相关文章

  1. SQL反模式学习笔记3 单纯的树

    2014-10-11 在树形结构中,实例被称为节点.每个节点都有多个子节点与一个父节点. 最上层的节点叫做根(root)节点,它没有父节点. 最底层的没有子节点的节点叫做叶(leaf). 中间的节点简 ...

  2. golang学习笔记14 golang substring 截取字符串

    golang学习笔记14 golang substring 截取字符串golang 没有java那样的substring函数,但支持直接根据 index 截取字符串mystr := "hel ...

  3. AC自动机学习笔记-2(Trie图&&last优化)

    我是连月更都做不到的蒟蒻博主QwQ 考虑到我太菜了,考完noip就要退役了,所以我决定还是把博客的倒数第二篇博客给写了,也算是填了一个坑吧.(最后一篇?当然是悲怆のnoip退役记啦QAQ) 所以我们今 ...

  4. POJ3376 Finding Palindromes —— 扩展KMP + Trie树

    题目链接:https://vjudge.net/problem/POJ-3376 Finding Palindromes Time Limit: 10000MS   Memory Limit: 262 ...

  5. Swift 2.0 字符串学习笔记(建议掌握OC字符串知识的翻阅)

    自己公司开现在使用OC语言在写,但Swift似乎是苹果更推荐使用的开发语言,估计也是未来开发的趋势,自己以前有接触swift,但又由于公司的项目赶,也没有时间去好好地学习这款开发语言.现在年底了,项目 ...

  6. Python学习笔记(二):字符串类型

    在上一篇随笔(https://www.cnblogs.com/g-qiang/p/10448813.html)中,说到 Python 有六种标准数据类型,而数字类型和字符串类型又是其中基本的数据类型. ...

  7. [Python学习笔记][第四章Python字符串]

    2016/1/28学习内容 第四章 Python字符串与正则表达式之字符串 编码规则 UTF-8 以1个字节表示英语字符(兼容ASCII),以3个字节表示中文及其他语言,UTF-8对全世界所有国家需要 ...

  8. Mysql高级操作学习笔记:索引结构、树的区别、索引优缺点、创建索引原则(我们对哪种数据创建索引)、索引分类、Sql性能分析、索引使用、索引失效、索引设计原则

    Mysql高级操作 索引概述: 索引是高效获取数据的数据结构 索引结构: B+Tree() Hash(不支持范围查询,精准匹配效率极高) 树的区别: 二叉树:可能产生不平衡,顺序数据可能会出现链表结构 ...

  9. knockoutJS学习笔记01:从拼接字符串到编写模板引擎

    开篇 关于knockout的文章,园里已经有很多大神写过了,而且都写得很好.其实knockout学习起来还是很容易的,看看官网的demo和园里的文章,练习练习就可以上手了(仅限使用,不包含研究源码). ...

  10. Swift学习笔记(4):字符串

    目录: 初始化 常用方法或属性 字符串索引 初始化 创建一个空字符串作为初始值: var emptyString = "" // 空字符串字面量 var anotherEmptyS ...

随机推荐

  1. Python做点击率数据预测

    点击率(Click-Through Rate, CTR)预测是推荐系统.广告系统和搜索引擎中非常重要的一个环节.在这个场景中,我们通常需要根据用户的历史行为.物品的特征.上下文信息等因素来预测用户点击 ...

  2. Docker安装mysql配置my.cnf并挂载到外部机器

    1.环境准备,创建外部挂载文件夹conf,data,log mkdir -p /data/dockerdata/mysql3306/{conf,data,log} 2.在/data/dockerdat ...

  3. jqurey基础知识和常用事件方法

    样式文件不需要<style>标签 引用style文件的方法 <link href="main.css" rel="stylesheet" st ...

  4. Linux驱动:使用workqueue、tasklet处理中断

    Linux驱动:使用workqueue.tasklet处理中断 背景 中断服务程序一般都是在中断请求关闭的条件下执行的,以避免嵌套而使中断控制复杂化.但是,中断是一个随机事件,它随时会到来,如果关中断 ...

  5. qt中的 connect 函数

    1.connect()函数实现的是信号与槽的关联. 注意:只有QO bject类及其派生的类才能使用信号和槽的机制 2.函数原型 static QMetaObject::Connection conn ...

  6. Redis 注册成windows 服务并开机自启动

    进入安装目录 输入命令redis-server --service-install redis.windows.conf   输入启动命令即可 redis-server --service-start ...

  7. JVM(Java虚拟机)整理(二):排错调优

    前言 上一篇内容:JVM(Java虚拟机)整理(一) Java 内存模型(JMM)详解 声明:本章节转载自 Info 上 深入理解Java内存模型.PDF文档下载 深入理解Java内存模型[程晓明] ...

  8. Exception in thread "main" java.lang.NoClassDefFoundError: io/netty/channel/EventLoopGroup

    最近在学习dubbo,跟着教程做,但是运行时报错,需要添加netty依赖 <dependency> <groupId>io.netty</groupId> < ...

  9. Mac Mysql初始化密码

    初始化密码 step1 苹果->系统偏好设置->最下面一行上点击mysql图标, 在弹出页面中 关闭mysql服务(点击stop mysql server) step2 登录终端:comm ...

  10. 2. C++的编译/链接模型

    C++的编译/链接模型 简单的加工模型 问题:无法处理大型程序 加工耗时较长 即使少量修改,也需要重新加工 解决方案:分块处理 好处 编译消耗资源,但一次处理输入较少 链接程序较多,但处理速度较快 便 ...