算法学习笔记(四)

给定一颗二叉树的头节点head,求符合搜索二叉树的最大结构的大小
class Node{
	int value;
	Node right;
	Node left;
    Node(int data){
    	this.value = data;
    }
}
class Record{
	int l;
	int r;
	Record(int _l,int _r) : l(_l), r(_r){}
}
int bstTopoSize2(Node head){
	unordered_map<Node,Record> map;
	return posOrder(head,map);
}
int posOrder(Node h,unordered_map<Node,Record> & map){
	if(h == null){
		return  0;
	}
	int ls = posOrder(h.left,map);
	int rs = posOrder(h.right,map);
	modifyMap(h.left,h.value,map,true);
	modifyMap(h.right,h.value,map,false);
	Record lr = map[h.left];
	Record rr = map[h.right];
	int lbst = lr == null ? 0 : lr.l + lr.r + 1;
	int rbst = rr == null ? 0 : rr.l + rr.r + 1;
	map.insert(h,new Record(lbst,rbst));
	return max(lbst + rbst + 1,max(ls,rs));
}
int modifyMap(Node h,int v,unordered_map<Node,Record> & map,bool s){
	if(h == null || (!map.contains(h))){
		return 0;
	}
	Record r = map[h];
	if((s && h.value > v) || ((!s) && h.value < v){
		map.erase(h);
		return r.l + r.r + 1;
	}else{
		int minus = modifyMap(s ? h.right : h.left, v, map,s);
		if(s){
			r.r = r.r - minus;
		}else{
			r.l = r.l - minus;
		}
		map.insert(h,r);
		return minus;
	}
}		
完美洗牌问题

3^k -1的偶数数有固定的触发点(3 ^ (k-1))
例如8: 1,3 ; 26: 1,3,9

int modifiyIndex1(int i,int len){
	if(i < len / 2){
		return 2 * i;
	}else{
		return 2 * ( i - (len / 2)) - 1;
}
int modifiyIndex2(int i,int len){
	return (2 * i) % (len + 1);
}
void shuffle(vector<int> & arr){
	if(arr != null && arr.size() != 0 && (arr.size() & 1) == 0){
		shuffle(arr,0,arr.size() - 1);
	}
}
void shuffle(vector<int> & arr,int l,int r){
	while(r - l + 1 > 0){
		int len = r - l + 1;
		int base = 3;
		int k = 1;
		while(base <= (len + 1) / 3){
			base *= 3;
			k ++;
		}
		int half = (base - 1) / 2;
		int mid = (l + r) / 2;
		rotate(arr, l + half,mid,mid + half);
		cycles(arr,l,base - 1,k);
		l = l + base - 1;
	}
}
void cycles(vector<int> & arr,int start,int len,int k){
	for(int i = 0,trigger = 1; i < k; i ++,trigger *= 3){
		int preValue = arr[trigger + start -1];
		int cur = modifyIndex2(trigger, len);
		while(cur != trigger){
			int tmp = arr[cur + start -1];
			arr[cur + start - 1] = preValue;
			preValue = tmp;
			cur = modifyIndex2(cur,len);
		}
		arr[cur + start -1] = preValue;
	}
}
void rotate(vectro<int>& arr,int start,int mid,int end){
	reverse(arr.begin() + start,arr.begin() + end);
	reverse(arr.begin() + start,arr.begin() + mid);
	reverse(arr.begin() + mid + 1,arr.begin() + end);
}		
给定一个无序数组,将数组变为第一个小于等于第二个数,第二个数大于等于第三个数,第三个数小于等于第四个数…

思路(空间复杂度O(1)):

  • 先将数组堆排序
  • 判断数组大小奇数偶数
  • 如果为偶数,直接将数组进行完美洗牌,并以两两一组对数组的数数字进行交换
  • 如果为奇数,第一个数不参与,将剩余数按照偶数的步骤进行
字符串匹配问题
bool isVaild(string &str,string & exp){
	for(int i = 0; i < str.size(); i++){
		if(str[i] == '*' || str[i] == '.'){
			return false;
		}
	}
	for(int i = 0;i < exp.size(); i++){
		if(exp[i] == '*' && (i == 0 || exp[i - 1] == '*'){
			return false;
		}
	}
	return true;
}
bool isMath(string str,string exp){
	if(str == null || exp == null){
		return false;
	}
	if(!isValid(str,exp)){
		return false;
	}
	int slen = str.size(),elen = exp.size();
	vector<vector<bool>> dp(slen + 1,vector<bool>(elen + 1false));
	dp[slen][elen] = true;
	for(int j = elen - 2;j >= 0;j -= 2){
		if(exp[j] != '*' && exp[j + 1] == '*'){
			dp[slen][j] = true;
		}else{
			break;
		}
	}
	if(slen > 0 && elen > 0){
		if(exp[elen - 1] == '.' || str[slen - 1] == exp[elen - 1]){
			dp[slen - 1][elen - 1] = true;
		}
	}

	for(int 
	for(int i = str.size() - 1; i >= 0;i--){
		for(int j = exp.size() - 2;j >= 0;j--){
			if(str[j + 1] != '*'){
				dp[i][j] = (str[i] == exp[j] || exp[j] == '.') && dp[i + 1][j + 1];
			}else{
				int si = i;
				while(si != str.size() && (str[si] == exp[j] || exp[j] == '.')){
					if(dp[si][j + 2]){
						dp[i][j] = true;
						break;
					}
					si ++;
				}
				if(dp[i][j] != true){
					dp[i][j] = dp[si][j + 2];
				}
			}
		}
	}
	return dp[0][0];
}	
给定一个数组,求最大异或和
class Node{
	Node nexts[2];
}
class NumTrie{
	Node head = new Node();
	void add(int num){
		Node cur = head;
		for(int move = 31; move >= 0;move --){
			int path = ((num >> move) & 1);
			cur.nexts[path] = cur.nexts[path] == null ? new Node() : cur.nexts[path];
			cur = cur.nexts[path];
		}
	}
	int maxXor(int sum){
		Node cur = head;
		int res = 0;
		for(int move = 31; move >= 0; move --){
			int path = (sum >> move) & 1;
			int best = move == 31 ? path : (path ^ 1);
			best = cur.nexts[path] != null ? best : (best ^ 1);
			res |= (path ^ best) << move;
			cur = cur.nexts[best];
		}
	}
}
int maxXorSubarray(vector<int> & arr){
	if(arr == null || arr.size() == 0){
		return 0;
	}
	int max = INT_MAX;
	int sum = 0;
	NumTire numTire = new NumTire();
	numTire.add(0);
	for(int i = 0; i < arr.size(); i ++){
		sum ^= arr[i];
		max = max (max,numTire.maxXor(sum));
		numTire.add(sum);
	}
	return max;
}		
气球得分问题

例如3,2,5
打3 32 ,打2 2 5,打5 5 最后得21
3 32,5 25 ,2 2, 18
2,325,3 3*5,5 50
…最后最高得分为50

int maxCoins(vector<int> & arr){
	if(arr == null || arr.size() == 0){
		return 0;
	}
	int n = arr.size();
	if(n == 1){
		arr[0];
	}
	vector<int> help(n + 2,1);
	for(int i = 0;i < n; i ++){
		help[i + 1] = arr[i];
	}
	return process(help,1,n);
}
int process(vector<int> & arr,int l,int r){
	if(l == r){
		return arr[l -1] * arr[l] * arr[r + 1];
	}
	int max = max(arr[l - 1] * arr[l] * arr[r + 1] + process(arr,l + 1,r),arr[l - 1] * arr[r] * arr[r + 1] + process(arr,l,r -1);
	for(int i = l + 1;i < r; i ++){
		max = max(max,arr[l - 1] * arr[i] * arr[r + 1] + process(arr,l,i - 1) + process(arr,i + 1, r));
	}
	return max;
}
给定数组判断是最优汉洛洛塔的第几步,无效返回-1
int process(vector<int> & arr,int i,int from,int other,int to){	
	if(i == -1){	
		return 0;
	}
	if(arr[i] != from && arr[i] != to){
		return -1;
	}
	if(arr[i] == from){
		return process(arr,i - 1,from,other,to);
	}else{
		int rest = process(arr, i - 1,other,from, to);
		if(rest == -1){
			return -1;
		}
		return (1 << i) + rest;
	}
}
给定两个字符串,判断是不是s2是否为s1的旋变字符串
int process(string &s1,string &s2,int l1,int l2,int size){
	if(size == 1){
		return s1[l1] == s2[l2];
	}
	for(int leftpart = 1;leftpart < size;leftpart ++){
		if((process(s1,s2,l1,l2,leftpart) && process(s1,s2,l1 + leftpart,l2 + leftpart,size - leftpart) || (process(s1,s2,l1,l2 + size - leftpart,leftpart) &&process(s1,s2,l1 + leftpart,l2,size - leftpart)){
			return true;
		}
	}
	return false;
}
bool sameTypeNumber(string &s1,string &s2){
	if(s1.length != s2.length){
		return false;
	}
	vector<int> cnt(256);
	for(char c : str1){
		cnt[c] ++;
	}
	for(char c : str2){
		if(--cnt[c] < 0){
			return false;
		}
	}
	return true;
}
bool isScreamble1(string &s1,string & s2){
	if((s1 == null && s2 != null) || (s1 != null && s2 == null){
		return false;
	}
	if(s1 == s2){
		return true;
	}
	if(!sameTypeNumber(s1,s2)){
		return false;
	}
	int n = s1.length;
	return process(s1,s2,0,0,n);
}	
给定两字符串,求s1中含有s2的所有字符的最小子串长度

滑动窗口,加个数

给定油数组和距离数组,路为环形,求一个合格的出发点数组(bool)

先计算两数组差,小于0的点一定不是合格出发点
定义rest,need,判断范围内是否联通
然后向两边扩张[start,end)
先向end方向扩张如果rest + nums[end] >0表示可以进入联通区域,小于0表示当前start不是合格出发点。
然后向start方向扩张,1、如果nums[start] < 0,则need += nums[start];该节点不是合格出发点。2、如果nums[start]>0,则判断该点是否与前面的出发点联通,如果可以则rest += nums[i] + need;重复向end的动作;
如果该点是合格出发点,则只需要向start的方向扩张,判断该点与合格点是否联通是则该点是合格出发点。
当判断到start 为end的前一个节点,如果前面没有合格出发点,则还没有判断的点也是不合格出发点

求线段的最大重叠问题

先将线段按照起始节点排序,然后定义一个有序表(储存线段的结尾位置,开始时为空)
依次遍历线段的节点,如果有序表中的节点有小于遍历节点的起始位置,则弹出有序表中小于起始位置的值。然后将该节点的结束 位置加入有序表,有序表节点的个数为重叠的线段的个数,重复该步骤直到结束。

求矩形重叠最大问题

先将矩形的右下节点排序,定义一个容器储存矩形
遍历矩形,将容器中所有矩形左上点的y小于等于当前矩形的右下删除,一直到不能删除时候,加入当前矩形。将容器所有矩形压缩为线段,求线段最大重叠问题。重复该步骤。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值