135 candy
题目大意是有n个孩子,每个孩子有一个rating值,现在需要给这n个孩子发糖果,要求如下:
- 每个孩子至少得到一个糖果
- 对于相邻的孩子的rating值高的应该得到更多的糖果
问发得最少糖果是多少?
解题思路是,对入任意一个孩子,如果他比左边连续p个孩子都高,比右边连续q个孩子都高,那么他至少得到min(p,q)+1个糖果,才能瞒住题目中的条件。
所以可以声明两个数组:
left[i]:记录从左边开始并以第i个孩子为结尾的严格递增的个数
right[i]:记录从右边开始并以第i个孩子为结尾的严格递增的个数
求得他们的时间复杂度为O(n),最后在一次计算一次每个孩子得到的最少糖果,时间复杂度为O(n).
int max(int a, int b){ return a>b?a:b; } int candy(int* ratings, int ratingsSize) { int left[ratingsSize], right[ratingsSize]; left[0] = 1; for(int i=1; i<ratingsSize; i++){ if(ratings[i] > ratings[i-1]){ left[i] = left[i-1] + 1; } else{ left[i] = 1; } } int ans = 0; right[ratingsSize-1] = 1; ans += max(left[ratingsSize-1], right[ratingsSize-1]); for(int i=ratingsSize-2; i>=0; i--){ if(ratings[i] > ratings[i+1]){ right[i] = right[i+1] +1; } else{ right[i] = 1; } ans += max(right[i], left[i]); } return ans; }
97 Interleaving String
题目大意是给出三个字符串s1,s2,s3,问是否可以有s1和s2交替组成s3。
这里的交替组成表示依次保持s1和s2中的字符的顺序,每次从s1和s2中取出若干字符组成s3即可,当然每个字符只能使用一次
使用动态规划解决这个问题:
dp[i][j]表示第一个字符串的前i个字符和第二个字符串的前j个字符,是否可以构成s3的前i+j个字符 递推公式如下: dp[i][j] = (s1[i] == s3[i+j+1] && dp[i-1][j]) || (s2[j] == s3[i][j-1] && dp[i][j-1])
时间复杂度为o(s1len * s2len)
bool isInterleave(char* s1, char* s2, char* s3) { int len1 = strlen(s1); int len2 = strlen(s2); int len3 = strlen(s3); if(len1 + len2 != len3) return false; bool dp[len1+1][len2+1]; dp[0][0] = true; //初始化 for(int i=0; i<len1; i++){ if(s1[i] == s3[i]) dp[i+1][0] = dp[i][0]; else dp[i+1][0] = 0; } for(int i=0; i<len2; i++){ if(s2[i] == s3[i]) dp[0][i+1] = dp[0][i]; else dp[0][i+1] = 0; } for(int i=0; i<len1; i++){ for(int j=0; j<len2; j++){ dp[i+1][j+1] = false; if(s2[j] == s3[i+j+1]) dp[i+1][j+1] = dp[i+1][j]; //注意,需要判断前面是否已经满足,满足就不要再进行查找了,不然会出现问题 if(s1[i] == s3[i+j+1] && !dp[i+1][j+1]) dp[i+1][j+1] = dp[i][j+1]; } } return dp[len1][len2]; }
316 Remove Duplicate Letters
题目大意是给你一个字符串(只包含小写字母),去掉重复的字符,处理后的字符串中的字符尽可能的按照字典序输出,但是需要保证原有的先后顺序,比如给出bca,得到字符串也就是bca,不能是abc。
思路一
假设给出字符串为s,长度为len,首先处理一遍字符串,得到所有出现的字符,然后将其按照字典序保存下来,记作ss,声明用来记录最终答案的字符串ret。
接下来按照一下步骤扩充ret:
1. 声明寻找字符区间[0,len]
2. 按照字典序取出一个存在与ss中的字符但没存在ret中的字符
3. 在处理区间中找到第一次出现的位置,并对其进行统计后面出现的字符满足一下条件的个数:存在ss中但不存在ret中(不包含自身)
4. 如果统计的个数为len(ss)- len(ret)-1,则将其加入到ret中,并跳转至2
5. 如果统计的个数不为len(ss)- len(ret)-1,取出下一个存在与ss中的字符但没存在ret中的字符,跳转至3
6. 直到ss中的字符和ret中的字符相同位置时间复杂度为O(k*k*n),其中k为返回字符串的长度小于26.
char* removeDuplicateLetters(char* s) { int vis[256]; int re[256][256]; for(int i=0; i<256; i++) vis[i] = 0; int len = strlen(s); int retlen = 0; for(int i=0; i<len; i++){ if(!vis[s[i]]){ vis[s[i]] = 1; retlen ++; } } char ss[retlen]; int tmp = 0; for(int i='a'; i<='z'; i++){ if(vis[i]){ ss[tmp++] = i; } } for(int i=0; i<retlen; i++){ vis[i] = 0; } int visch[256]; for(int i=0; i<256; i++){ visch[i] = 0; } tmp = 0; char *ret = malloc(sizeof(char)*(retlen+1)); int now = 0; while(tmp < retlen){ int rem = retlen - tmp - 1; //printf("%d %d\n", now, rem); int i = 0; for(; i<retlen; i++){ if(vis[i]) continue; //printf("%d %c:", i, ss[i]); int cnt = 0; int j = now; for(; j<len; j++){ if(s[j] == ss[i]) break; } //printf("j-%d\n",j); j++; int next = j; int v[256]; for(int k=0; k<256; k++){ v[k] = 0; } for(; j<len; j++){ // printf("pre:j:%d s[j]:%c ss[i]:%c visch[s[j]]:%d v[s[j]]:%d\n", j, s[j], ss[i], visch[s[j]], v[s[j]]); if(s[j] == ss[i] || visch[s[j]]) continue; if(!v[s[j]]){ cnt++; v[s[j]] = 1; } // printf("aft:j:%d s[j]:%c ss[i]:%c visch[s[j]]:%d v[s[j]]:%d\n", j, s[j], ss[i], visch[s[j]], v[s[j]]); } //printf("cnt-%d\n",cnt); if(cnt == rem) { now = next; break; } } // printf("update:%d %c ----------------->\n", i, ss[i]); ret[tmp++] = ss[i]; visch[ss[i]] = 1; vis[i] = 1; } ret[tmp] = 0; return ret; }
思路二
对于字符串的每个位置,维护一个cnt值,表示其后面出现不同字符的个数,每次选出
- cnt值最大的
- 字典序最小的
- 下标最小的
作为返回的下一个字符,并一次从上次查找到字符的地方开始找下一个字符
时间复杂度为O(k*n)
char* removeDuplicateLetters(char* s) { int vis[27],v[27];//vis for the ret and v for the current for(int i=0; i<27; i++){ vis[i] = 0; v[i] = 0; } int retsize = 0; char *ret = malloc(sizeof(char)); int now = 0; int len = strlen(s); while(now < len ){ int cnt = 0; for(int i=0; i<27; i++){ v[i] = 0; } int next = len-1; for(int i=len-1; i>=now; i--){ //忽略已经拥有的字母 if(vis[s[i]-'a']) continue; //统计出现的频率 if(!v[s[i]-'a']){ v[s[i]-'a'] = 1; cnt++; next = i; } else{ if(s[i] <= s[next]) next = i; } } if(cnt == 0) break; retsize ++; ret = realloc(ret, sizeof(char)*retsize); ret[retsize-1] = s[next]; vis[s[next]-'a'] = 1; now = next+1; } ret = realloc(ret, sizeof(char)*(retsize+1)); ret[retsize] = 0; return ret; }