给定一个数组,1<=a[i]<=n,找到所有未出现的数字个数
int process(vector<int> & arr){
if(arr == null || arr.size() == 0){
return 0;
}
for(auto x: arr){
modify(x,arr);
}
int res = 0;
for(int i = 0;i < arr.size(); i++){
if(arr[i] != i + 1){
res ++;
}
}
}
void modify(int x,vector<int> & arr){
while(arr[x - 1] != value){
int tmp = arr[x - 1];
arr[x - 1] = x;
x = tmp;
}
}
打赏问题
1、花费a ,人气+2
2、花费b,人气*2
3、花费c,人气-2
到指定值所用的最少花费
int minCoins(int add,int times,int del,int start,int end){
if(start > end){
return -1;
}
return process(0,end,add,times,del,start,end * 2,((end - start) / 2) * add);
}
int process(int preMoney,int end,int add,int times,int del,int start,int limitAim,int limitCoin){
if(preMoney > limitCoin || start < 0 || start >limitAim){
return INT_MAX;
}
if(start == end){
return preMoney;
}
int min = INT_MAX;
int p1 = process(preMoney + add,end,add,times,del,start + 2,limitAim,limitCoin);
if(p1 != INT_MAX){
min = p1;
}
int p2 = process(preMoney + add,end,add,times,del,start - 2,limitAim,limitCoin);
if(p2 != INT_MAX){
min = min(p1,p2);
}
int p3 = process(preMoney + add,end,add,times,del,start * 2,limitAim,limitCoin);
if(p3 != INT_MAX){
min = min(min,p3);
}
return min;
}
最大奖励
第一项为n(项目个数)和d(最大天数)
第二行到n+1项为活动信息 花费时间t、获得奖励a,后n项为当前项目与其他项目是否有依赖
输出最大奖励和时间
从后往前遍历整个图,每个节点都保留奖励和花费,最后从中选出最大奖励和时间
给定一个字符串(0,1,&,|,^),添加括号得到期望结果的方法次数
int num1(string s,bool desired){
if(s == null || s.size() == 0){
return 0;
}
if(!isvalid(s)){
return 0;
}
return p(s,desired,0,s.size() - 1);
}
bool isvalid(string s){
if((s.size() & 1) == 0){
return false;
}
for(int i = 0;i < s.size(); i += 2){
if((s[i] != '1') && (s[i] != '0')){
return false;
}
}
for(int i = 1;i < s.size();i += 2){
if((s[]i] != '&') && (s[i] != '|') && (s[i] != '^')){
return false;
}
}
return true;
}
int p(string &s,bool disired,int l,int r){
if(l == r){
if(s[l] == '1'){
return disired ? 1 : 0;
}else{
return disired ? 0 : 1;
}
}
int res = 0;
if(disired){
for(int i = l + 1;i < r; i += 2){
swtich(s[i]){
case '&':
res += p(s,true,l,i - 1) * p(s,true, i + 1, r);
break;
case '|':
res += p(s,true,l,i - 1) * p(s,true, i + 1, r);
res += p(s,false,l,i - 1) * p(s,true, i + 1, r);
res += p(s,true,l,i - 1) * p(s,false, i + 1, r);
break;
case '^' :
res += p(s,true,l,i - 1) * p(s,false, i + 1, r);
res += p(s,false,l,i - 1) * p(s,true, i + 1, r);
break;
}
}
}else{
for(int i = l + 1;i < r; i += 2){
swtich(s[i]){
case '&':
res += p(s,true,l,i - 1) * p(s,false, i + 1, r);
res += p(s,false,l,i - 1) * p(s,true, i + 1, r);
res += p(s,false,l,i - 1) * p(s,false, i + 1, r);
break;
case '|':
res += p(s,false,l,i - 1) * p(s,false, i + 1, r);
break;
case '^' :
res += p(s,true,l,i - 1) * p(s,true, i + 1, r);
res += p(s,false,l,i - 1) * p(s,false, i + 1, r);
break;
}
}
}
return res;
}
最长不重复子串
int maxUnique(string s){
if(s == null || s.size() == 0){
return 0;
}
vector<int> map(256, -1);
int len = 0,pre = -1,cur = 0;
for(int i = 0;i < s.size();i ++){
pre = max(pre,map[s[i]];
cur = i - pre;
len = max(len cue);
map[s[i]] = i;
}
return len;
}
任意给两个字符串,将两个字符串相等,可以有替换、删除、添加,每种操作都有代价,求最小代价
int mincost(string s1,string s2,int ic,int dc,int rc){
if(s1 == null || s2 == null){
return 0;
}
int row = s1.size() + 1;
int col = s2.size() + 1;
vector<vector<int>> dp(row,vector<int>(col,0));
for(int i = 1;i < row; i++){
dp[i][0] = dc * i;
}
for(int j = 1; j < col; j++){
dp[0][j] = ic * j;
}
for(int i = 1; i < row; i++){
for(int j = 1; j < col; j++){
if(s1[i - 1] == s2[j - 1]){
dp[i][j] = dp[i - 1] [j - 1];
}else{
dp[i][j] = dp[i - 1][j - 1] + rc;
}
dp[i][j] = min(dp[i][j],dp[i][j - 1] + ic);
dp[i][j] = min(dp[i][j],dp[i - 1][j] + dc);
}
}
return dp[row - 1][col - 1];
}
字符串每个字符都保留一个,并且让最后的结果字典序最小
string remove(string str){
if(str == null || str.size() < 2){
return str;
}
vector<int> map(256,0);
for(int i = 0; i < str.size(); i ++){
map[str[i]] ++;
}
int minASCIIndex = 0;
for(int i = 0; i < str.size(); i++){
if(--map[str[i]] == 0){
break;
}else{
minASCIIndex = str[minASCIIndex] > str[i] ? i : minASCIIndex;
}
}
return str[minASCIIndex] + remove(str.substr(minASCIIndex + 1).replaceAll(str[minASCIIndex],'');
字符问题
a 为1 b为2,c为3, ab 为27… abc(不存在ba,cba),给一个字符串求是第几个
int g(int i,int len){
int sum = 0;
if(len == 1){
return 1;
}
for(int j = i + 1;j <= 26;j++){
sum += g(j,len - 1);
}
return sum;
}
int f(int len){
int sum = 0;
for(int i = 1; i < 26; i ++){
sum += g(i,len);
}
return sum;
}
int kst(string s){
int sum = 0,len = s.size();
for(int i = 1;i < len; i ++){
sum += f(i);
}
int first = str[0] - 'a' + 1;
for(int i = 0; i< first;i ++){
sum += g(i,len);
}
int pre = first;
for(int i = 1; i < len ;i ++){
int cur = s[i] - 'a' + 1;
for(int j = pre + 1; j < cur; j++){
sum += g(j, len - i);
}
pre = cur;
}
return sum;
}
给一个数组,排序后相邻两个数之间的差值最大,O(n),不能使用非基于比较的排序
int maxGap(vector<int> nums){
if(nums == null || nums.size() == 0){
return 0;
}
int len = nums.size();
int min = INT_MIN,max = INT_MAX;
for(int i = 0; i < len;i++){
max = max(max,nums[i]);
min = min(min,nums[i]);
}
if(min == max){
return 0;
}
vector<bool> hasNum(len + 1,false);
vector<int> maxs(len + 1);
vector<int> mins(len + 1);
for(int i = 0;i < len; i++){
bid = bucket(nums[i],len,min,max);
mins[bid] = hasNum[i] ? min(mins[bid],nums[i]) : nums[i];
maxs[bid] = hasNum[i] ? max(maxs[bid],nums[i]) : nums[i];
hasNum[bid] = true;
}
int res = 0;
for(int i = 1;i <= len;i ++){
if(hasNum[i]){
res = max(res,mins[i] - maxs[i - 1])
}
}
return res;
}
int bucket(long num,long len,long min,long max){
return (int)((num - min) * len / (max - min));
}
给出n个数字,问最多有多少不重叠的非空区间,异或和为0的个数
int mostEOR(vector<int> & arr){
int xor = 0;
int n = arr.size();
vector<int> dp(n + 1, 0);
unordered_map<int,int> map;
map.insert(0,-1);
for(int i = 0; i < n; i++){
xor ^= arr[i];
if(map.contains(xor)){
int pre = map[xor];
dp[i] = pre == -1 ? 1 : (dp[pre] + 1);
}
if(i > 0){
dp[i] = max(dp[i], dp[i - 1]);
}
map.insert(xor, i);
}
return dp[n];
}
硬币问题
现有n1 + n2种面值的硬币,前n1种无限多枚,后n2只有一枚,可以拼出m的方法数
int main(vector<int>& arr1,vector<int> & arr2,int m){
int n1 = arr1.size();
int n2 = arr2.size();
vector<int> dp1(m,0);
vector<int> dp2(m,0);
dp1[0] = 1;
dp2[0] = 1;
for(int i = 1;i <= n1; i++){
for(int j = arr1[i]; j <= m; j++){
dp1[j] += dp1[j - arr1[i]];
}
}
for(int i = 1; i <= n2;i++){
for(int j = m;j >= arr2[i]; j--){
dp2[j] += dp2[j - arr2[i];
}
}
int res = 0;
for(int i = 0; i <= m; i++){
res += dp1[i]*dp[m - i];
}
return res;
}
给定两个排序好的数组,均从小到大排序,求两数组的最小的k个数字
int findKthNum(vector<int> & arr1,vector<int> & arr2,int kth){
if(arr1 == null || arr2 == null){
return -1;
}
if(kth < 1 || kth > arr1.size() + arr2.size()){
return -1;
}
vector<int> longs == arr1.size() >= arr2.size() ? arr1 : arr2;
vector<int> shorts == arr1.size() < arr2.size() ? arr1 : arr2;
int l = longs.size();
int s = shorts.size();
if(kth <= s){
return getUpmedian(shorts,0,kth - 1,longs, 0, kth - 1);
}
if(kth > 1){
if(shorts[kth - l - 1] >= longs[l - 1]){
return shorts[kth - l - 1];
}
if(longs[kth - s - 1] >= shorts[s - 1]){
return longs[kth - s - 1];
}
return getUpmedian(shorts,kth - 1,s - 1,longs, kth - 1, l - 1);
}
if(longs[kth - s - 1] >= shorts[s -1]){
return longs[kth - s - 1];
}
return getUpmedian(shorts,0,s - 1,longs, kth - s, kth - 1);
}
int getUpmedian(vector<int> & a1,int s1,int e1,vector<int> & a2,int s2,it e2){
int mid1 = 0,mid2 = 0;
int offset = 0;
while(s1 < e1){
mid1 = (s1 + e1) >> 1;
mid2 = (s2 + e2) >> 1;
offset = ((e1 - s1 + 1) & 1) ^ 1;
if(a1[mid1] > a2[mid2]){
e1 = mid1;
s2 = mid2 + offset;
}else if(a1[mid1] < a2[mid2]){
s1 = mid1 + offset;
e2 = mid2;
}else{
return a1[mid1];
}
}
return mid(a1[s1],a2[s2]);
}
给一个循环链表,每次干掉一个,求最后剩下的节点。
Node josephusKill(Node head,int m){
if(head == null || head.next == head || m < 1){
return head;
}
Node cur = head.next;
int tmp = 1;
while(cur != head){
tmp ++;
cur = cur.next;
}
tmp = getLive(tmp, m);
while( -- tmp != 0){
head = head.next;
}
head = head.next;
return head;
}
int getLive(int i, int m){
if(i == 1){
return 1;
}
return (getLive(i - 1,m) + m - 1) % i + 1;
}
给一个数组和n个人,每次干掉一个(干掉的是根据数组的值决定),求最后剩下的节点。
int live(int n,vector<int> & arr){
return no(n,arr,0);
}
int no(int i,vector<int> & arr,int index){
if(i == 1){
return 1;
}
// 老 = ( 新 + m - 1 ) % i - 1;
return (no(i,arr,nextIndex(arr.size(),index) + arr[i] - 1) % i + 1;
}
int nextIndex(int size,int index){
return index == size - 1 ? 0 : index + 1;
}
给定一个三元组求大楼轮廓线
[start,end,hight]
class Nodes{
int start;
bool isAdd;
int h;
Nodes(int _start,bool _isAdd,int _h): start(_start),isAdd(_isAdd),h(_h){}
}
vector<vector<int>> buildOutline(vector<vector<int>> &matrix){
vector<Nodes> nodes(matrix.size() * 2);
for(int i = 0; i < matrix.size(); i++){
nodes[i * 2] = new Node(matrix[i][0],true,matrix[i][2]);
nodes[i * 2 + 1] = new Node(matrix[i][1],false,matrix[i][2]);
}
sort(nodes.begin(),nodes.end(),[&](Nodes a1,Nodes a2){
if(a1.start != a2.start){
return a1.start - a2.start;
}
if(a1.isAdd != a2.isAdd){
return a1.isAdd ? -1 : 1;
}
return 0;
});
map<int,int> mapHeightTimes,maxXHeight;
for(int i = 0;i < nodes.size(); i++ ) {
if(nodes[i].isAdd){
if(!mapHeightTimes.contains(nodes[i].h)){
mapHeightTimes.insert(nodes[i].h, 1);
}else{
mapHeightTimes[nodes[i].h] ++;
}
}else{
if(mapHeightTimes[nodes[i].h] == 1){
mapHeightTimes.erase(nodes[i].h);
}else{
mapHeightTimes[nodes[i].h] --;
}
}
if(maxXHeight.empty()){
maxXHeight.insert(nodes[i].start,0);
}else{
auto it = maxXHeight.end();
it --;
maxXHeight.put(nodes[i].start,it.second);
}
vector<vector<int>> res;
vector<int> path;
int start = 0 ,preHeight = 0;
for(auto &[cur, curh] : maxXHeight){
if(preHeight != curh){
if(preHeight != 0){
path.push_back(start);
path.push_back(cur);
path.push_back(preHeight);
}
start = cur;
preHeight = curh;
}
}
return res;
}
给定正数数组,求得到指定值的最长子串长度
int getMaxLength(vector<int> & arr,int k){
if(arr == null || arr.size() == 0 || k <= 0){
return 0;
}
int left = 0,right = 0;
int sum = arr[0],len = 0;
while(right < arr.size()){
if(sum == k){
len = max(len, right - left + 1);
sum -= arr[left ++];
}else if(sum < k){
right ++;
if(right > arr.size())[
break;
}
sum += arr[right];
}else{
sum -= arr[left ++];
}
}
return len;
}
求数组中,小于等于指定值的最长子数组
int getMaxLength(vector<int> & arr,int k){
if(arr == null || arr.size() == 0){
return 0;
}
int n = arr.size();
vector<int> minSums(n),minSumEnds(n);
minSums[n - 1] = arr[n - 1];
minSumEnds[n - 1] = n - 1;
for(int i = n - 2; i >= 0; i--){
if(minSums[i + 1] < 0){
minSums[i] = arr[i] + minSums[i + 1];
minSumEnds[i] = minSumEnds[i + 1];
}else{
minSums[i] = arr[i];
minSumEnds[i] = i;
}
}
int end = 0,sum = 0,res = 0;
for(int i = 0;i < n; i++){
while(end < n && sum + minSums[end] <= k){
sum += minSums[end];
end = minSumEnds[end] + 1;
}
res = max(res, end - i);
if(end > i){
sum -= arr[i];
}else{
end = i + 1;
}
}
return res;
}
给定一个二维数组,有正负,给定一个机器人,机器人可以将值变为相反数(一次机会),求最长路径,只可以向右、右上、右下移动
class info{
int no;
int yes;
info(int x,int y): no(x),yes(y){}
}
int snake(vector<vector<int>> & arr){
int ans = INT_MAX;
vector<vector<info>> dp(arr.size(),vector<info>(arr[0].size()));
for(int row = 0; row < arr.size();row ++){
for(int col = 0; col < arr[0].size(); col ++){
auto cur= f(arr,row,col,dp);
ans = max(ans,max(cur.no,cur.yes));
}
}
return ans;
}
info f(vector<vector<int>> & arr,int row,int col,vector<vector<info>> &dp){
if(dp[row][col] != null){
return dp[row][col];
}
if(col == 0){
dp[row][col] = new info(arr[row][col],-arr[row][col]);
return dp[row][col];
}
int preNo = -1,preYes = -1;
if(row > 0){
info leftUp = f(arr,row - 1,col -1,dp);
if(leftUp.no >= 0){
preNo = leftUp.no;
}
if(leftUp.yes >= 0){
preYes = leftUp.yes;
}
}
info left = f(arr,row,col - 1,dp);
if(left.no >= 0){
preNo = max(preNo,left.no);
}
if(left.yes >= 0){
preYes = max(preYes,left.yes);
}
if(col > 0){
info leftDown = f(arr,row + 1,col-1,dp);
if(leftDown.no >= 0){
preNo = max(preNo,leftDown.no);
}
if(left.yes >= 0){
preYes = max(preYes,leftDown.yes);
}
}
int no = -1,yes = -1;
if(preNo >= 0){
no = preNo + arr[row][col];
yes = preNo + (- arr[row][col]);
}
if(preYes >= 0){
yes = max(yes, preYes + arr[row][col]);
}
info cur = new info(no,yes)
dp[row][col] = cur;
return cur;
}
给定一个合法算式求值
vector<int> value(string &str,int i){
stack<string> que;
int num = 0;
vector<int> bra;
while(i < str.size() && str[i] !=')'){
if(str[i] >= '0' && str[i] <= '9'){
num = num * 10 + str[i ++] -'0';
}else if(str[i] != '('){
addNum(que,num);
que.push(str[i ++]);
num = 0;
}else{
bra = value(str, i + 1);
num = bra.front();
i = bra.back() + 1;
}
}
add(que, num);
return {getNum(que), i};
}
int addNum(stack<string> & st,int num){
if(!st.empty()){
int cur = 0;
string top = st.top();
st.pop();
if(top == "+" || top == "-"){
st.push(top);
}else{
cur = stoi(st.top());
st.top();
num = top == "*" ? (cur * num) : (cur / num);
}
}
st.push(to_string(num);
}
int getNum(stack<int> & st){
int res = 0;
bool add = false;
string cur;
while(!st.empty()){
cur = st.top();
st.pop();
if(cur == "+"){
add = true;
}else if(cur == "-"){
add = false;
}else{
num = stoi(cur);
res += add ? num : -num;
}
}
return res;
}
给定一条船,最多装2个人,做多载重为limit,给定一个重量数组,求最少需要船数
int minBoat(vector<int & arr,int limit){
sort(arr.begin(),arr.end());
if(arr == null || arr.size() == 0){
return 0;
}
if(arr[arr.size() - 1] <= limit/2){
return (arr.size() + 1) >> 1;
}
if(arr[0] > limit / 2){
return arr.size();
}
int lessR = -1;
for(int i = arr.size() - 1;i >= 0; i--){
if(arr[i] <= (limit / 2)){
lessR = i;
break;
}
}
int L = lessR;
int r = lessR + 1;
int lessUnused = 0;
while(L >= 0){
int solved = 0;
while(R < arr.size() && arr[L] + arr[R] <= limit){
R ++;
solved ++;
}
if(solved == 0){
lessUnused ++;
L --;
}else{
L = max( -1, L - solved);
}
}
int lessAll = lessR + 1;
int lessUsed = lessAll - lessUnused;
int mostUnsolved = arr.size() - lessR - 1 - lessUsed;
return lessUsed + ((lessUnused + 1) >> 1) + mostUnsolved;
}
求无序数组的第k小的数(bfprt)
int select(vector<int> & arr,int begin,int end,int i){
if(begin == end){
return arr[begin];
}
int pivot= medianOfMedians(arr,begin,end);
int[] pivotRange = patition(arr,begin,end,pivot);
if(i >= pivotRange[0] && i <= pivotRange[1]){
return arr[i];
}else if(i < pivotRange[0]){
return select(arr,begin,pivotRange[0] - 1, i);
}else{
return select(arr,pivotRange[1] + 1,end,i);
}
}
int medianOfMedians(vector<int> & arr,int begin,int end){
int num = end - begin;
int offset = num % 5 == 0 ? 0 : 1;
vector<int> mArr(num / 5 + offset);
for(int i = 0; i < mArr.size(); i++){
int beginI = begin + i * 5;
int endI = beginI + 4;
mArr[i] = getMedian(arr,beginI,min(end,endI));
}
return select(mArr,0,mArr.size() - 1,mArr.size() / 2);
}
int[] patition(vector<int> & arr,int begin,int end,int povit){
int small = begin - 1;
int cur = begin;
int big = end + 1;
while(cur != big){
if(arr[cur] < povit){
swap(arr, ++small,cur ++);
}else(arr[cur] > povit){
swap(arr, cur,--big);
}else{
cur ++;
}
}
int range[2] = {small + 1,big - 1};
return range;
}
int getMedian(vector<int> & arr,int begin,int end){
sort(arr.begin() + begin,arr.begin() + end);
int sum = begin + end;
int mid = (sum >> 1) + (sum &1);
return arr[mid];
}
裂开问题
1 : 1(1)
2: 1,1;2(2)
3:1,1,1;1,2;3;(3)
4:1,1,1,1;1,1,2;1,3;2,2;4(5)
int ways(int n){
if(n < 1){
retun 0;
}
vector<vector<int>> dp(n + 1,vector<int>(n + 1);
for(int pre = 1; pre < dp.size(); pre ++){
dp[pre][0] = 1;
dp[pre][pre] = 1;
}
for(int pre = n - 1; pre > 0;pre --){
for(int rest = pre + 1;rest <= n;rest ++){
dp[pre][rest] = dp[pre + 1][rest] + dp[pre][rest - pre];
}
}
return dp[1][n];
}