Skip to content

Commit b65b810

Browse files
author
Xianfeng Zhao
committed
pull request to merge code and resolve conflict in Readme
1 parent 40d41e7 commit b65b810

File tree

48 files changed

+1288
-129
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1288
-129
lines changed

Binary_Search/483.Smallest-Good-Base/483.Smallest Good Base.cpp

Lines changed: 15 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,45 +2,29 @@ class Solution {
22
public:
33
string smallestGoodBase(string n)
44
{
5-
long long N=0;
6-
for (int i=0; i<n.size(); i++)
7-
N=N*10+n[i]-'0';
8-
9-
if (N==1) return "2";
10-
11-
long long m_max = log(N+1)/log(2)+1;
12-
13-
for (long long m=m_max; m>=2; m--)
5+
long long N = stoll(n);
6+
for (int m = log(N+1)/log(2); m>=2; m--)
147
{
158
long long left = 2;
16-
long long right = pow(N,1.0/(m-1));
17-
long long mid;
18-
19-
// cout<<"m="<<m<<" "<<left<<" "<<right<<" "<<endl;
20-
21-
while (left<=right) // 两个边界都需要探查
9+
long long right = pow(N, 1.0/(m-1));
10+
while (left<=right)
2211
{
12+
long long mid = left+(right-left)/2;
13+
long long k = mid;
2314

24-
mid = left+(right-left)/2;
25-
long long k=mid;
26-
long long sum=1;
15+
long long sum = 1;
2716
for (int i=1; i<m; i++)
28-
{
29-
sum=sum*k+1;
30-
}
31-
if (sum==N)
32-
return to_string(k);
33-
else if (sum<N)
34-
left = mid+1;
35-
else
36-
right = mid-1; // 注意,因为mid已经排除,所以right的更新值不应该包括mid本身,否则死循环。
37-
38-
//cout<<sum<<" "<<k<<" "<<m<<" "<<endl;
39-
17+
sum = sum*k + 1;
18+
19+
//cout<<m<<" "<<" "<<k<<" "<<sum<<endl;
20+
21+
if (sum==N) return to_string(k);
22+
else if (sum>N) right = mid-1;
23+
else left = mid+1;
4024
}
25+
4126
}
4227

4328
return to_string(N-1);
44-
4529
}
4630
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
class Solution {
2+
public:
3+
int lp(string&s, int state)
4+
{
5+
string t;
6+
for (int i=0; i<s.size(); i++)
7+
{
8+
if ((state>>i)&1)
9+
t.push_back(s[s.size()-1-i]);
10+
}
11+
12+
int n = t.size();
13+
vector<vector<int>>dp(n, vector<int>(n));
14+
for (int i=0; i<n; i++)
15+
dp[i][i] = 1;
16+
for (int len=2; len<=n; len++)
17+
for (int i=0; i+len-1<n; i++)
18+
{
19+
int j = i+len-1;
20+
if (t[i]==t[j])
21+
dp[i][j] = dp[i+1][j-1]+2;
22+
else
23+
dp[i][j] = max(dp[i][j-1], dp[i+1][j]);
24+
}
25+
26+
return dp[0][n-1];
27+
}
28+
29+
30+
int maxProduct(string s)
31+
{
32+
int n = s.size();
33+
int all = (1<<n)-1;
34+
int ret = 0;
35+
for (int subset=1; subset<(1<<n)-1; subset++)
36+
ret = max(ret, lp(s, all-subset)*lp(s, subset));
37+
return ret;
38+
}
39+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
### 2002.Maximum-Product-of-the-Length-of-Two-Palindromic-Subsequences
2+
3+
因为只有12个字符,我们可以暴力枚举拆解的方案,也就是2^12=4096种方法,将原字符串拆为两个subsequence。然后查看每个subsequence里面最长的回文子序列。
4+
5+
对于一个subsequence里面的最长回文子序列问题,我们可以将这个子序列收拢转化为一个常规的字符串。求字符串里的最长回文子序列,这是一个经典问题。可以用o(N^2)的DP。
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
class Solution {
2+
int k;
3+
string s;
4+
string ret;
5+
public:
6+
string longestSubsequenceRepeatedK(string s, int k)
7+
{
8+
this->k = k;
9+
this->s = s;
10+
vector<int>count(26);
11+
for (auto ch:s)
12+
count[ch-'a']++;
13+
string t;
14+
for (int i=0; i<26; i++)
15+
{
16+
if (count[i]>=k)
17+
t.push_back('a'+i);
18+
}
19+
20+
string temp;
21+
dfs(t, temp);
22+
23+
return ret;
24+
}
25+
26+
void dfs(string&t, string& temp)
27+
{
28+
if (temp!="" && !checkOK(temp))
29+
return;
30+
31+
if (temp.size()>ret.size() || (temp.size()==ret.size() && temp>ret))
32+
ret = temp;
33+
34+
if (temp.size()==7)
35+
return;
36+
37+
for (auto ch: t)
38+
{
39+
temp.push_back(ch);
40+
dfs(t, temp);
41+
temp.pop_back();
42+
}
43+
}
44+
45+
bool checkOK(string& temp)
46+
{
47+
int j = 0;
48+
int count = 0;
49+
for (int i=0; i<s.size(); i++)
50+
{
51+
if (s[i]!=temp[j]) continue;
52+
j++;
53+
if (j==temp.size())
54+
{
55+
j = 0;
56+
count++;
57+
if (count == k)
58+
return true;
59+
}
60+
}
61+
return false;
62+
}
63+
};
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
### 2014.Longest-Subsequence-Repeated-k-Times
2+
3+
本题其实并没有特别高明的算法,就是“暴力”枚举可能的repeated subsequence,然后检验该子序列能否在s中重复k次。显然对于“检验”的操作,复杂度就是o(n)=16000,那么枚举repeated subsequence的复杂度是多少呢?
4+
5+
注意到本题的约束条件```n < k*8```. 这说明了两点:首先,repeated subsequence的长度不超过7,否则重复k次之后会有```n>=len(subsequenc)*k>=8*k```推出矛盾。其次,s里面频次大于等于k的字符种类不会超过7,否则也会有```n>=k*8```推出矛盾。这两个推论告诉我们,repeated subsequence的构造并没有那么复杂,它最长只有7位,并且字符的种类不会超过7种。所以repeated subsequence的可能性最多就是7^7+7^6+7^5...= 7^8 = 5e6。
6+
7+
按照上面的分析,共有5e6种可能的subsequence,每次检验需要1.6e4,总的时间复杂度依然达到了1e10数量级。我们只能寄希望于剪枝,降低subsequence的种类数目。其中一种方法就是,如果我们发现一个较短的subsequence不符合条件(即无法重复k次依然是s的子序列),那么任何在此基础上append任何字符也都不会符合条件。所以这就提醒我们“暴力”枚举repeated subsequence可以采用从短的序列逐渐生成更长序列的方法,一旦检验发现不合条件,就可以终止这个支路。

Dynamic_Programming/115.Distinct-Subsequences/115.Distinct-Subsequences.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,27 @@ class Solution {
44
{
55
int m = s.size();
66
int n = t.size();
7-
auto dp = vector<vector<long>>(m+1,vector<long>(n+1,0));
7+
auto dp = vector<vector<long long>>(m+1,vector<long long>(n+1,0));
88
s = "#"+s;
99
t = "#"+t;
10+
11+
if (m<n)
12+
return 0;
13+
if (m==n)
14+
return (s==t);
1015

11-
for (int i=0; i<=m; i++) dp[i][0] = 1;
16+
for (int i=0; i<=m; i++)
17+
dp[i][0] = 1;
1218

1319
for (int i=1; i<=m; i++)
1420
for (int j=1; j<=n; j++)
1521
{
1622
if (s[i]==t[j])
17-
dp[i][j] += dp[i-1][j-1];
18-
dp[i][j] += dp[i-1][j];
23+
dp[i][j] = dp[i-1][j] + dp[i-1][j-1];
24+
else
25+
dp[i][j] = dp[i-1][j];
26+
//cout<<i<<" "<<j<<" "<<dp[i][j]<<endl;
1927
}
20-
2128
return dp[m][n];
2229
}
2330
};
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
class Solution {
2+
public:
3+
int minNumberOfSemesters(int n, vector<vector<int>>& dependencies, int k)
4+
{
5+
vector<int>dp(1<<n, INT_MAX/2);
6+
vector<int>prevState(1<<n, 0);
7+
vector<int>prevCourse(n,0);
8+
9+
for (auto x: dependencies)
10+
prevCourse[x[1]-1] |= 1<<(x[0]-1);
11+
12+
for (int state = 0; state < (1<<n); state++)
13+
{
14+
prevState[state] = 0;
15+
for (int i=0; i<n; i++)
16+
{
17+
if ((state>>i) & 1)
18+
prevState[state] |= prevCourse[i];
19+
}
20+
if (prevState[state]==0 && __builtin_popcount(state)<=k)
21+
dp[state] = 1;
22+
}
23+
24+
dp[0] = 0;
25+
for (int state = 1; state < (1<<n); state++)
26+
{
27+
for (int subset = state; subset > 0; subset = (subset-1)&state)
28+
{
29+
if (__builtin_popcount(state) - __builtin_popcount(subset) <= k && (prevState[state] & subset) == prevState[state])
30+
{
31+
dp[state] = min(dp[state], dp[subset]+1);
32+
}
33+
}
34+
}
35+
return dp[(1<<n)-1];
36+
}
37+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
class Solution {
2+
public:
3+
int minSessions(vector<int>& tasks, int sessionTime)
4+
{
5+
int n = tasks.size();
6+
vector<int>dp((1<<n), INT_MAX/2);
7+
for (int state=0; state<(1<<n); state++)
8+
{
9+
int sum = 0;
10+
for (int i=0; i<n; i++)
11+
{
12+
if ((state>>i)&1)
13+
sum+=tasks[i];
14+
}
15+
if (sum<=sessionTime)
16+
dp[state]=1;
17+
}
18+
19+
for (int state=1; state<(1<<n); state++)
20+
{
21+
for (int subset=state; subset>0; subset=(subset-1)&state)
22+
{
23+
dp[state] = min(dp[state], dp[subset]+dp[state-subset]);
24+
}
25+
}
26+
return dp[(1<<n)-1];
27+
28+
}
29+
};
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
### 1986.Minimum-Number-of-Work-Sessions-to-Finish-the-Tasks
2+
3+
因为数据规模n<=14,考虑到3^14是4e6数量级,可以判定这是非常套路的“枚举子集”的动态规划问题。
4+
5+
我们用长度为14的二进制数state的每个bit位表示该任务是否被实施,那么dp[state]表示state所代表的任务集合需要最少多少个session。
6+
7+
利用枚举子集的模板:
8+
```cpp
9+
for (int state=1; state<(1<<n); state++)
10+
for (int subset=state; subset>0; subset=(subset-1)&state)
11+
{
12+
dp[state] = DoSomething(dp[subset]);
13+
}
14+
```
15+
dp[state]如果对应着多个session,那么它必然可以“拆分”成两个任务集subset与state-subset,然后对各自所需的session数目进行相加。所以我们需要遍历state的所有subset,找到最优的一种拆分。即```dp[state]=min{dp[subset]+dp[state-subset]}```。注意,上述的枚举子集的框架,所需要的时间复杂度是o(3^n)而不是o(2^n)
16+
17+
初始值:对于一些特定的任务组合state,如果总时间小于sessionTime,那么他们的dp[state]就是1. 其余的dp[state]我们都设置为无穷大。这需要花费2^n的时间预处理遍历所有的组合。。
18+
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using LL = long long;
2+
class Solution {
3+
LL M = 1e9+7;
4+
public:
5+
int numberOfUniqueGoodSubsequences(string binary)
6+
{
7+
int n = binary.size();
8+
string s = "#" + binary;
9+
vector<LL>dp(n+1,0);
10+
11+
int start = 1;
12+
while (start <=n && s[start]=='0')
13+
start++;
14+
if (start==n+1) return 1;
15+
dp[start] = 1;
16+
17+
int last0 = 0;
18+
int last1 = 0;
19+
20+
for (int i=start+1; i<=n; i++)
21+
{
22+
int j = (s[i]=='0')? last0:last1;
23+
dp[i] = dp[i-1] *2 - (j>=1 ? dp[j-1]:0);
24+
dp[i] = (dp[i] + M) % M;
25+
26+
if (s[i]=='0') last0 = i;
27+
else last1 = i;
28+
}
29+
30+
return dp[n] + (binary.find("0")!=-1);
31+
}
32+
};

0 commit comments

Comments
 (0)