算法学习笔记(三)

本文涉及一系列算法问题,包括数组中未出现数字的计数、最优化操作策略、字符串处理、最长不重复子串、字符串转换、数组排序后的最大差值、异或和为0的区间数量、硬币组合、最小成本字符串转换、循环链表节点操作以及数组相关计算。这些问题涵盖了数据结构和算法的多个方面,如搜索、排序、动态规划和图论等。
摘要由CSDN通过智能技术生成
给定一个数组,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];
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值