双指针算法 一个简单的例子
算法思想 输入一行字串如“abc def ghi” 将单词输出即 abc def ghi ※思路,定义两个指针,i指向第一个单词,j向后扫描,如果扫到’ ‘空格就停下来,然后输出i到j-1包含的单词,然后使i = j进入下一层循环。\
完整代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <iostream> #include <string> #include <cstring> using namespace std;int main () { char str[100 ]; gets (str); int n = strlen (str); for (int i =0 ;i < n;i ++){ int j = i; while (j < n && str[j] != ' ' ) j++; for (int k = i;k < j;k ++) cout << str[k]; cout << endl; i = j; } return 0 ; }
最长连续不重复子序列
算法思想 ※每次都枚举i,j从0开始。 ※用s[]数组记录当前[j,i]中数的个数,当i前移时时s[a[i]]++,当s[a[i]] > 1时,说明区间内有重复的数,则让s[a[j]]–,然后使j往前移动,重复上述操作。 ※不重复序列的长度res = max(res,i - j + 1),因为i比j大
完整代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <iostream> using namespace std;const int N = 1e6 + 10 ;int a[N];int s[N];int n;int main () { cin >> n ; for (int i = 0 ;i < n;i ++) scanf ("%d" ,&a[i]); int res = 0 ; for (int i = 0 ,j = 0 ;i < n;i ++){ s[a[i]] ++; while (s[a[i]] > 1 ){ s[a[j]] --; j++; } res = max (res,i - j + 1 ); } cout << res << endl; return 0 ; }
位运算 求n的二进制表示中的第k位数字 算法思想 ※求n的二进制表示中的第k位数字:n >> k & 1
①先把第k位移到最后一位:n >> k;
②看个位是几: x & 1
完整代码 1 2 3 4 5 6 7 8 9 #include <iostream> using namespace std;int main () { int n = 10 ; for (int k = 3 ;k >= 0 ;k --) cout << (n >> k & 1 ); return 0 ; }
返回n的最后一位1 算法思想 ※返回n的最后一位1:lowbit(n) -> n & - n
例题
完整代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <iostream> using namespace std;int lowbit (int x) { return x & -x; }int main () { int n; cin >> n; while (n --){ int x; cin >> x; int res = 0 ; while (x) x -= lowbit (x),res ++ ; cout << res << endl; } return 0 ; }
离散化 ※加1的话,从1开始映射,不加1的话,从0开始映射
算法思想 1.介绍
离散化,把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率。通俗的说,离散化是在不改变数据相对大小的条件下,对数据进行相应的缩小。离散化本质上可以看成是一种哈希。 2.算法 ※unique函数是将数组中所有元素去重,返回去重之后数组的尾端点,使用unique函数必须先排序。 ※erase函数是删除unique函数返回的尾端点与数组尾端点的值,也就是删除重复元素
例题
完整代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 #include <iostream> #include <vector> #include <algorithm> using namespace std;const int N = 3e6 + 10 ;int n ,m;int a[N],s[N];typedef pair<int ,int > PII; vector<int > alls; vector<PII> add,query; int find (int x) { int l = 0 ,r = alls.size () - 1 ; while (l < r){ int mid = l + r >> 1 ; if (alls[mid] >= x) r = mid; else l = mid + 1 ; } return r + 1 ; }int main () { cin >> n >> m; for (int i = 0 ;i < n;i ++){ int x,c; cin >> x >> c; add.push_back ({x, c}); alls.push_back (x); } for (int i = 0 ;i < m;i ++){ int l,r; cin >> l >> r; query.push_back ({l, r}); alls.push_back (l); alls.push_back (r); } sort (alls.begin (),alls.end ()); alls.erase (unique (alls.begin (),alls.end ()),alls.end ()); for (auto item : add){ int x = find (item.first); a[x] += item.second; } for (int i = 1 ;i <= alls.size ();i ++) s[i] = s[i - 1 ] + a[i]; for (auto item : query){ int l = find (item.first), r = find (item.second); cout << s[r] - s[l - 1 ] << endl; } return 0 ; }
区间合并
算法思想 ※图解 1.按区间左端点排序 2.扫描整个区间,扫描过程中,把所有可能有交集的区间进行合并
完整代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #include <iostream> #include <vector> #include <algorithm> using namespace std;typedef pair<int ,int > PII;const int N = 1e6 + 10 ;int n ; vector<PII> segs;void merge (vector<PII> &segs) { vector<PII> res; sort (segs.begin (),segs.end ()); int st = -2e9 ,ed = -2e9 ; for (auto seg:segs){ if (ed < seg.first){ if (st != -2e9 ) res.push_back ({st,ed}); st = seg.first,ed = seg.second; } else { ed = max (ed,seg.second); } } if (st != -2e9 ) res.push_back ({st,ed}); segs = res; }int main () { cin >> n; for (int i = 0 ;i < n;i ++){ int l,r; cin >> l >> r; segs.push_back ({l,r}); } merge (segs); cout << segs.size () << endl; return 0 ; }