Jostree

  • Home

  • Tags

  • Categories

  • Archives

  • Search

当离散遇见连续

Posted on 2018-07-11 | Edited on 2018-07-15

在连续的空间中,我们可以说一条曲线是连续的、是可导的或者可微的,并且可以计算出曲线上一点的导数。那么离散的数列空间是否也具有这相同优美的性质呢?数列是具有类似于连续空间中的微分特性么? 如何使用积分的思想计算多项式的累加和?幂积分与等比数列求和有什么联系?连续空间中的对数函数在离散空间中对应着什么?在下面的部分中,我们将搭建起离散空间和连续空间的桥梁,欣赏这离散空间的美。

微分与差分

我们定义微分算子:

\[ D f(x) = \lim_{h \to 0} \frac{f(x + h) - f(x)}{h} \]

在离散空间中,我们限制了\(h\)的取值只能为正整数,因此\(h \to 0\)时,\(h=1\)是该极限最接近的值,从而我们定义差分算子:

\[ \Delta f(x) = f(x + 1) - f(x) \]  在连续空间的传统微积分中,我们有微分运算:

\[D(X^m) = mx^{m-1}\]

很不幸,在离散空间中却没有如此优美的结果:

\[\Delta(x^3) = (x+1)^3 - x^3 = 3x^2 + 3x + 1\]

是哪里出错了么?我们重新审视连续空间中幂的定义,把\(h\)添加进幂的定义中,我们发现:

\[x^m = \prod_{k=0}^{m - 1}\lim_{h \to 0}(x-kh)\]

其中符号\(\prod\)表示连乘(例如\(\prod_{k=1}^{3}k=1*2*3\)),离散空间中我们限制了\(h\)的取值只能为正整数,因此\(h \to 0\)时,我们只能取\(h=1\),从而我们定义一种在离散空间的新运算等价于连续空间的幂运算:

\[x^{\underline{m}} = \prod_{k=0}^{m - 1}(x-k)\]

这不就是排列数么?!原来连续空间中的幂对应与离散空间就是排列数,有\(x\)个不同的硬币,我们依次选出\(m\)个,总共的选择方法有:

\[ \begin{aligned} & x * (x-1) * \dots * (x - (m - 1)) \\ =& \prod_{k=0}^{m-1} x-k \\ =& x^{\underline{m}} \end{aligned} \]

我们称新运算\(x^{\underline{m}}\)为下降幂,终于下降幂运算在差分算子中得到了优美的结果:

\[ \begin{aligned} & \Delta(x^{\underline{m}})\\ =& (x+1)^{\underline{m}} - x ^{\underline{m}}\\ =& (x+1)x \dots (x-m+2) - x \dots (x-m+2)(x-m+1)\\ =& (x+1)x^{\underline{m-1}} - x^{\underline{m-1}}(x-m+1)\\ =&mx^{\underline{m-1}} \end{aligned} \]

积分与求和

连续空间中微分算子\(D\)有一个逆,叫作积分算子\(\int\),积分算子与微分算子的关系为

\[g(x) = Df(x) \Leftrightarrow \int g(x)dx = f(x) + C\]

对应于离散空间,\(\Delta\)也有一个逆,叫做求和算子\(\sum\),求和算子与差分算子的关系为

\[g(x) = \Delta f(x) \Leftrightarrow \sum g(x)\delta x = f(x) + C\]

在\(x\)的取值处,\(C\)为常数,当我们进行差分运算时,如同微分运算,常数会被消去。

连续空间中也有定积分

\[\int_a^b g(x)dx = f(x) \big| _a^b = f(b) - f(a) \]

同样,对于离散空间,我们也定义相似的算子确定和

\[\sum_a^b g(x)\delta x = f(x) \big|_a^b = f(b) - f(a)\]

下面我们来探索算子\(\sum_a^bg(x)\delta\)究竟有什么直观的意义呢? 我们发现当\(a\)和\(b\)是正整数,且\(b\ge a\)时

\[\sum_a^bg(x)\delta x= \sum_{k=1}^{b-1}g(k)= \sum_{a\ge k > b}g(k)\]

在连续空间中的定积分公式

\[\int_0^n x^m dx = \frac{n^{m+1}}{m+1}\]

应用第一节中的下降幂算子得到了离散空间中另一个优美的公式:

\[\sum_{0 \ge k > n} k ^{\underline{m}} = \frac {k^{\underline{m+1}}}{m+1} \bigg|_0^n = \frac{n^{m+1}}{m+1}\]

这个优美的公式可以解决离散空间的求和问题,当\(m=1\)时,\(k^{\underline{1}} = k\)即:

\[\sum_{0 \ge k > n}k = \frac{n^{\underline{2}}}{2} = n(n-1)/2\]

这不就是高斯求和公式么?我们用离散空间和这种优雅的方式得到了它,进一步任何幂次的求和公式我们都可以计算

\[k^2 = k^{\underline{2}} + k^{\underline{1}}\]

从而

\[ \begin{aligned} & \sum_{0 \ge k > n}k^2 \\ =& \sum_{0 \ge k > n}k^{\underline{2}} + k^{\underline{1}}\\ =& \frac{n^{\underline{3}}}{3} +\frac{n^{\underline{2}}}{2} \\ =& \frac{1}{3}n(n-\frac{1}{2})(n-1) \end{aligned} \]

你得到了它!

负数下降幂与离散空间中的自然对数

我们定义的下降幂公式:

\[x^{\underline{n}} = x^{\underline{n + 1}} / (x - n)\]

不妨对n小于等于0的情况进行推广,从而可以得到如下表格

\[ \begin{array}{ll} \hline \hline n & x^{\underline{n}} \\\hline \hline 0 & 1 \\\hline -1 & x^{\underline{-1}} = \frac{1}{(x+1)} \\\hline -2 & x^{\underline{-2}} = \frac{1}{(x+1)(x+2)} \\\hline -3 & x^{\underline{-3}} = \frac{1}{(x+1)(x+2)(x+3)} \\\hline \hline \end{array} \]

对于负数下降幂,差分性质依然成立:

\[ \begin{aligned} \Delta x^{-2} &= \frac{1}{(x+2)(x+3)} - \frac{1}{(x+1)(x+2)} \\ &= \frac{(x+1) - (x+3)}{(x+1)(x+2)(x+3)} \\ &= -2x^{\underline{-3}} \end{aligned} \]

同样,对于负数下降幂求和公式仍然成立:

\[\sum_{a}^b x ^{\underline{m}} \delta x = \frac {x^{\underline{m+1}}}{m+1} \bigg|_a^b, m \neq -1 \]

在连续空间中,若\(m=-1\)我们有

\[\int_a^b x^{-1} dx = \ln x \bigg|_a^b\]

在离散空间中我们希望找到相同的功能的函数,他需要满足:

\[x^{\underline{-1}} = \frac{1}{x+1} = \Delta f(x) = f(x+1) - f(x)\]

从而我们得到:

\[f(x) = \frac{1}{1} + \frac{1}{2} + \dots + \frac{1}{x}\]

定义函数\(f(x)\)在\(x\)为正整数时的调和数,定义为\(H_x\),他等价于连续空间中的\(\ln(x)\)

从而我们可以得到下降和的完全描述:

\[ \sum_a^b x^{\underline{m}} \delta x = \left\{ \begin{aligned} \frac{x^{\underline{m+1}}}{m+1} \bigg|_a^b && , m \neq -1 \\ H_x \bigg|_a^b &&, m = -1 \end{aligned} \right. \]

在连续空间中,我们有\(D e^x = e^x\)在连续空间中,我们是否也存在一个函数具有\(\Delta f(x) = f(x)\)呢? \[ f(x+1) - f(x) = f(x) \Leftrightarrow f(x + 1) = 2f(x) \]

久违的结果!在离散空间中\(f(x) = 2^x\)等价于连续空间中的\(f(x) = e^x\) ,而离散空间中的2就等价与连续空间中的自然对数\(e\)。

总结

我们在这里总结连续空间中的各种微积分形式在离散空间中对应的查分求和形式

\[ \begin{array}{lll} \hline \hline 说明 & 连续空间 & 离散空间 \\ \hline \hline 微分 \Leftrightarrow 差分 & D f(x) = \lim_{h \to 0} \frac{f(x + h) - f(x)}{h} & \Delta f(x) = f(x + 1) - f(x) \\\hline 积分 \Leftrightarrow 求和 & g(x) = Df(x) \Leftrightarrow \int g(x)dx = f(x) + C & g(x) = \Delta f(x) \Leftrightarrow \sum g(x)\delta x = f(x) + C \\\hline 定积分 \Leftrightarrow 限定求和 & \int_a^b g(x)dx = f(x) \big|_a^b = f(b) - f(a) & \sum_a^b g(x)\delta x = f(x) \big|_a^b = f(b) - f(a) \\\hline 幂 \Leftrightarrow 下降幂 & x^m & x^{\underline{m}} \\\hline 幂微分 \Leftrightarrow 下降幂差分 & D (x^m) = m x^{m-1} & \Delta (x^{\underline{m}}) = mx^{\underline{m-1}} \\\hline 自然对数 \Leftrightarrow 离散对数 & e & 2 \\\hline 自然对数函数 \Leftrightarrow 离散调和函数 & \ln(x) = \log_e(x) & H(x) = \frac{1}{1} + \frac{1}{2} + \dots + \frac{1}{x}\\\hline 幂积分 \Leftrightarrow 下降幂求和 (m \neq -1)& \int_a^b x^m dx = \frac{x^{m+1}}{m+1} \big|_a^b = \frac{b^{m+1}-a^{m+1}}{m+1} & \sum_{a \ge x > b} x ^{\underline{m}} \delta x = \frac {x^{\underline{m+1}}}{m+1} \big|_a^b = \frac{b^{\underline{m+1}} - a^{\underline{m+1}}}{m+1} \\\hline 幂积分 \Leftrightarrow 下降幂求和 (m = -1)& \int_a^b x^m dx = \int_a^b \frac{1}{x} dx = \ln(x) \big|_a^b = \ln(b) - \ln(a) & \sum_{a \ge x > b} x ^{\underline{-1}} \delta x = H(x) \big|_a^b = H(b) - H(a) \\\hline 指数函数积分 \Leftrightarrow 等比数列求和 (c \neq 1)& \int_a^b m^x = \frac{m^x}{\ln(m)} \big|_a^b = \frac{m^b - m^a}{\ln(m)}& \sum_{a \ge x > b} m^x \delta x = \frac{m^x}{m-1}\big|_a^b = \frac{m^b - m^a}{m-1} \\\hline \hline \end{array} \]

Eular质数筛法

Posted on 2016-04-09 | Edited on 2018-06-23 | In 数论
如何在o(n)的时间内求得n以内得质数?
Read more »

素数测试

Posted on 2016-04-03 | Edited on 2018-06-23 | In 数论

费马小定理

如果p是素数,a是小于p的正整数,那么a^(p-1) mod p = 1。

首先我们证明这样一个结论:如果p是一个素数的话,那么对任意一个小于p的正整数a,a, 2a, 3a, ..., (p-1)a除以p的余数正好是一个1到p-1的排列。例如,5是素数,3, 6, 9, 12除以5的余数分别为3, 1, 4, 2,正好就是1到4这四个数。

反证法,假如结论不成立的话,那么就是说有两个小于p的正整数m和n使得na和ma除以p的余数相同。不妨假设n>m,则p可以整除a(n-m)。但p是素数,那么a和n-m中至少有一个含有因子p。这显然是不可能的,因为a和n-m都比p小。

用同余式表述,我们证明了: (p-1)! ≡ a * 2a * 3a * … * (p-1)a (mod p) 也即: (p-1)! ≡ (p-1)! * a^(p-1) (mod p) 两边同时除以(p-1)!,就得到了我们的最终结论: 1 ≡ a^(p-1) (mod p)

Miller-Rabbin 素数测试

如果p是素数,x是小于p的正整数,且x^2 mod p = 1,那么要么x=1,要么x=p-1。这是显然的,因为x^2 mod p = 1相当于p能整除x^2-1,也即p能整除(x+1)(x-1)。由于p是素数,那么只可能是x-1能被p整除(此时x=1)或x+1能被p整除(此时x=p-1)。

从而我们选取不同的x,对p其进行进行素数测试,即可。代码如下:

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <ctime>

using namespace std;
typedef long long LL;
const int S = 100;

LL mul(LL a, LL b, LL n)
{
LL res = 0;
while( b )
{
if( b & 1 )
{
res += a;
res %= n;
}
a = (a + a) % n;
b = b >> 1;
}
return res;
}

LL pow(LL a, LL b, LL n)
{
LL res = 1;
while( b )
{
if( b & 1 )
{
res = mul(res, a, n);
}
a = mul(a, a, n);
b = b >> 1;
}
return res;
}

bool miller_rabbin(LL n)
{
if( n == 2 ) return true;
if(n < 2 || !(n & 1)) return false;
int t = 0;
LL a, x, y, u = n - 1;
while((u & 1) == 0) t++, u>>=1;
for( int i = 0 ; i < S ; i++ )
{
a = rand() % (n - 1) + 1;
x = pow(a, u, n);
for( int j = 0 ; j < t ; j++ )
{
y = mul(x, x, n);
if( y == 1 && x != 1 && x != n - 1 )
{
return false;
}
x = y;
}
if( x != 1 ) return false;
}
return true;
}


int main(int argc, char *argv[])
{
int T;
scanf("%d", &T);
LL N;
srand(time(0));
while( T-- )
{
cin>>N;
if( miller_rabbin(N) )
{
cout<<"Yes"<<endl;
}
else
{
cout<<"No"<<endl;
}
}
}

n个数组元素最大和的Topk

Posted on 2016-03-23 | Edited on 2018-06-23

两个数组的问题

对于两个递减数组A, B, 分别有m, n个元素,共有m * n个和,我们想求前k大的和,我们可以列出所有的和。

A0B0 > A0B1 > A0B2 > A0B3 > A0B4 ... A1B0 > A1B1 > A1B2 > A1B3 > A1B4 ... A2B0 > A2B1 > A2B2 > A2B3 > A2B4 ... ...

我们把第一行压入优先队列,然后优先队列的第一个一定是和最大的,A0B0,弹出他。然后把A0B0下面的数A1B0压入优先队列,我们可以保证第二大的一定在优先队列中,因为优先队列里面的值都是当列中最大的一个,从而循环即可。

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
class Sum
{
public:
int val;
int Ai;
int Bi;
friend bool operator < (Sum a, Sum b)
{
return a.val < b.val;
}
};

vector<int> maxSum(vector<int> A, vector<int> B, int n)
{
vector<int> res;
if( A.size() == 0 )
{
return res;
}
priority_queue<Sum, vector<Sum>, less<Sum> > qu;
for( int i = 0 ; i < B.size() ; i++ )
{
Sum tmp;
tmp.val = A[0] + B[i];
tmp.Ai = 0;
tmp.Bi = i;
qu.push(tmp);
}
while( res.size() < n )
{
res.push_back(qu.top().val);
Sum tmp = qu.top();
qu.pop();
if( ++tmp.Ai < A.size() )
{
tmp.val = A[tmp.Ai] + B[tmp.Bi];
qu.push(tmp);
}
}
return res;
}

对于n个数组

我们先对前两个取前k大的数,在和下面的合并取最大的数,直到取完第n个数组即可。

概率采样问题

Posted on 2016-03-22 | Edited on 2018-06-23

从n个数中等概率选取1个数,n未知

如果元素总数是n,那么每个元素备选到的概率应该是1/n, 然而N只有遍历结束时才会知道,于是我们可以利用乘法公式凑出1/n:

\[ p_i = \frac{1}{i} \times \frac{i}{i+1} \times \frac{i+1}{i+2} \times \dots \times \frac{n-1}{n} = \frac{1}{n} \]

在从前向后遍历的过程中,不断的根据概率改变我们的候选元素,第i个元素被最终选中的概率计算公式恰好为上式。

可以从代码简单实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class RandomSelectOne
{
public:
int count;
int selected;
RandomSelectOne():count(0){}
void add(int num)
{
count++;
if(rand() % count == 0)
selected = num;
}
int getSelected()
{
return selected;
}
}

从n个数中等概率的选取m个数,n未知

我们只需要把selected扩展成一个数组即可,对于第i个元素,其被选择的概率值为:

\[ p_i = \frac{m}{i} \times \frac{i}{i+1} \times \dots \times \frac{n-1}{n} \ \ \ \ i > m\]

\[ p_i = \frac{1}{1} \times \frac{m}{m+1} \times \frac{m+1}{m+2} \times \dots \times \frac{n-1}{n} \ \ \ \ i \leq m\]

对于前m个数,直接加入候选,这个数出现在最终候选名单的概率为每次加入新的值时,该数都没有没选中。对于m以后的数,被选进来的概率为m/i,在以后每次加入新数时,都没有被选中,即可以有上式表示。

代码如下:

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
class RandomSelect
{
public:
int count;
int scount;
vector<int> selected;
RandomSelect(int m):count(0), scount(m){}
void add(int num)
{
count++;
if(selected.size() < scount)
{
selected.push_back(num);
}
else
{
int idx = rand() % count;
if( idx < scount )
{
selected[idx] = num;
}
}
}
vector<int> getSelected()
{
return selected;
}
};

带权的n个数随机选取一个数的问题,n未知

设元素总数为n,当然在遍历结束前n是未知的。设第 \(i(1 \leq i \leq n)\) 个元素的权重为 \(w_i\) ,则权重总和为\(w=\sum_{i=1}^n w_i\) ,也是在遍历结束时才知道的。根据题目要求,第\(i\)个元素被选取的概率应该等于\(pi=\frac{w_i}{w}\)。

如果最终被选择的是第i个元素,那么必须在遍历到它时,恰好被选中:

\[\frac{w_i}{w} = \frac{w_i}{\sum_{k=1}^i w_k}\]

另外,在处理后面的元素时,第i个元素没有被替换掉,对于任意的\(j( i < j \leq n )\),第i个元素都不会被选中,其概率为:

\[\frac{w-w_j}{w} = \frac{\sum_{k = 1} ^ {j - 1} w_k}{\sum_{k = 1} ^ j w_k} \]

从而第i个元素最终被选择的概率为:

\[p_i = \frac{w_i}{\sum_{k=1}^n w_i}\]

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class RandomSelectOne
{
public:
double totalWeight;
int selected;
RandomSelectOne():totalWeight(0.0){}
void add(int num, double weight)
{
totalWeight += weight;
if(rand() % 10000 / 10000.0 * totalWeight < weight)
selected = num;
}
int getSelected()
{
return selected;
}
};

带权的n个数随机选取m个数,n未知

当m=2时,第i个元素被选中有两种情况,第一次被选中,第一次未被选中,第二次被选中,从而可以得到:

\[p_i(2) = \frac{w_i}{w} + \sum_{j \neq i} (\frac{w_j}{w} \times \frac{w_i}{w-w_j})\]

也可以计算\(\bar{p}\)表示不被选中的概率:

\[\bar{p}_i(2) = \sum_{j \neq i} (\frac{w_j}{w} \times \frac{w - w_j - w_i}{w - w_j})\]

很容易得到\(p_i(2) + \bar{p}_i(2) = 1\)

当m>2时,元素i未被选中的概率为:

\[\bar{p}_i(m) = \sum_{j_1}(\frac{w_{j_1}}{w} \sum_{j_2} ( \frac{w_{j_2}}{w-w_{j_1}} \sum_{j_3} (\frac{w_{j_2}}{w-w_{j_1}-w_{j_2}} \dots \sum_{j_m} \frac{w_{j_m}}{w - \sum_{k=1}^{m-1} w_{j_k}})))\]

二叉树转双向链表

Posted on 2016-03-20 | Edited on 2018-06-23
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
class Node
{
public:
int val;
Node * left;
Node * right;
Node(){val = 0;left = NULL; right = NULL;}
};

Node * process(Node * head)
{
if( head == NULL ) return NULL;
Node * l = process(head->left);
Node * r = process(head->right);
if( l && r )
{
head->left = l;
head->right = r->right;
r->right->left = head;
r->right = l->right;
l->right = head;
return r;
}
else if( l )
{
head->left = l;
head->right = l->right;
l->right = head;
return head;
}
else if( r )
{
head->left = NULL;
head->right = r->right;
r->right = head;
return r;
}
else
{
head->right = head;
head->left = NULL;
return head;
}
}

Node * tree2list(Node * head)
{
if( head == NULL ) return NULL;
Node *last = process(head);
head = last->right;
last->right = NULL;
return head;
}

多个数组的元素全组合

Posted on 2016-03-16 | Edited on 2018-06-23

题目:

给定n个数组,从每个数组中取出一个元素,并进行组合,最终返回所有可能的组合。

递归解法:

简单的dfs即可,当深度到达n时,即把当前字符串添加到最终结果中。 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
void merge1(vector<string> & res, string cur, const vector<vector<char> > &arr, int depth)
{
if( depth == arr.size() )
{
res.push_back(cur);
}
for( int i = 0 ; i < arr[depth].size() ; i++ )
{
cur += arr[depth][i];
merge1(res, cur, arr, depth+1);
cur.pop_back();
}
}

非递归解法

可以用一个队列保存结果信息,每次从队列头取出一个字符串,然后与第i个数组中的每个元素进行组合,然后在压入队列中,注意使用一个#号表示组合完了一个数组。 代码如下:

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
vector<string> merge2(vector<vector<char> > & arr)
{
vector<string> res;
if( arr.size() == 0 )
{
return res;
}
queue<string> qu;
for( int i = 0 ; i < arr[0].size() ; i++ )
{
string tmp = "";
tmp += arr[0][i];
qu.push(tmp);
}
qu.push("#");
for( int i = 1 ; i < arr.size() ; i++ )
{
while( qu.front() != "#")
{
if( arr[i].size() == 0 )
{
qu.push(qu.front());
}
else
{
for( int j = 0 ; j < arr[i].size() ; j++ )
{
qu.push(qu.front() + arr[i][j]);
}
}
qu.pop();
}
qu.pop();
qu.push("#");
}
while( qu.front() != "#")
{
res.push_back(qu.front());
qu.pop();
}
return res;
}

二分查找及其变种

Posted on 2016-03-07 | Edited on 2018-06-23

要点

  1. 每次查找范围一定要缩小,如果另mid = l 或 mid = r时,查找范围为长度为1时会陷入死循环。
  2. 如果写成 l < r , 当查找范围长度为1时,会导致找不到key。
  3. 写成mid = l + (r - l)/2,可防止整数溢出。
  4. 使用ans保存已经符合条件的最后的mid,最后返回即可。

查找符合条件的位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int binary(int * arr, int val, int l, int r)
{
if(arr == NULL || r < 0) return -1;
int mid = 0;
while(l <= r)
{
mid = l + (r - l)/2;
if(arr[mid] == val)
{
return mid;
}
else if(arr[mid] > val)
{
r = mid - 1;
}
else
{
l = mid + 1;
}
}
return -1;
}

查找符合要求的最小位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int binary(int * arr, int val, int l, int r)
{
if(arr == NULL || r < 0) return -1;
int mid = 0;
int ans = -1;
while( l <= r )
{
mid = l + (r - l)/2;
if(arr[mid] >= val)
{
ans = mid;
r = mid - 1;
}
else
{
l = mid + 1;
}
}
return ans;
}

查找符合要求的最大的位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int binary(int * arr, int val, int l, int r)
{
if(arr == NULL || r < 0) return -1;
int mid = 0;
int ans = -1;
while(l <= r)
{
mid = l + (r - l)/2;
if(arr[mid] <= val)
{
ans = mid;
l = mid + 1;
}
else
{
r = mid - 1;
}
}
return ans;
}

leetcode 3. Longest Substring Without Repeating Characters

Posted on 2016-03-01 | Edited on 2018-06-23 | In leetcode

题目

Given a string, find the length of the longest substring without repeating characters. For example, the longest substring without repeating letters for "abcabcbb" is "abc", which the length is 3. For "bbbbb" the longest substring is "b", with the length of 1.

题解

设定两个指针l, r, 设定一个hash表,表示当前区间[l, r]中出现的字母的次数,每次r向右移动一位,当发现hash表中存在该字母时,移动l,并更新hash表,直到hash表中没出现过该字母,一直进行下去,直到r到达字符串结尾。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
int lengthOfLongestSubstring(string s) {
vector<int> vis(256,0);
int l = 0;
int r = 0;
int res = 0;
while(r < s.size())
{
while(vis[s[r]] == 1)
{
vis[s[l]]--;
l++;
}
vis[s[r]] = 1;
r++;
res = max(res,r - l);
}
return res;
}
};

leetcode 2. Add Two Numbers

Posted on 2016-03-01 | Edited on 2018-06-23 | In leetcode

题目

You are given two linked lists representing two non-negative numbers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.

Input: (2 -> 4 -> 3) + (5 -> 6 -> 4) Output: 7 -> 0 -> 8

题解

两个指针,向后扫描,注意进位,当到了最后一个节点时,若进位等于1,则应该创建新节点,并赋值为1。 可以使用头结点,以方便while循环规则。

代码

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
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
int carry = 0;
int sum = 0;
ListNode * res = new ListNode(0);
ListNode * cur = res;
while(l1 || l2 || carry)
{
sum = carry;
carry = 0;
if(l1)
{
sum += l1->val;
l1 = l1->next;
}
if(l2)
{
sum += l2->val;
l2 = l2->next;
}
if(sum > 9)
{
sum -= 10;
carry = 1;
}
cur->next = new ListNode(sum);
cur = cur->next;
}
ListNode * tmp = res;
res = res->next;
delete tmp;
return res;
}
};
12
Liu Yi

Liu Yi

Happy Coding

12 posts
2 categories
10 tags
© 2016 — 2018 Liu Yi
Powered by Hexo v3.7.1
|
Theme — NexT.Mist v6.3.0