面试题6

#ifndef _MS_6_
#define _MS_6_


#include <iostream>
#include <cassert>
#include <algorithm>
#include <list>
#include <queue>


using namespace std;


void TestMS_6();


/*
	通配符:
		1.*:0个或多个字母
		2.?:1个任意字母
	如果遇到*,如何匹配?1.找到*后面的第一个字母c,从
	另一个中找到所有c出现的位置,挨个尝试
*/
int Scan(const char *text, const  char *name);




/*
	给一个有N个整数的数组S,和另一个整数X,判断S中有没有
	2个数的和为X,O(NlogN)
	1.排序
	2.首尾两个指针
*/
/*
	两个数组,N个数,是否存在一个相同的数:O(NlogN)
	1.排序
	2.类似于归并过程
*/
/*
	排序N个比N^7小的数,O(N)
	桶排序?
*/
void BaseSort(int *arr, int size, int N);


// 对第i位进行排序
/*
	1.
*/




/*
	N个数,M个筐子,每个筐子至少一个
*/
void EggsInBasket(int eggs, int *ans, int basket, int index, int remain);


void PrintIntArr(int *arr, int size);


void TestEggsInBasket();


// 返回结果数
int MachineDelivery(int *R, int *O, bool *map, int size, int remain, int *ans, int step);


void TestMachineDelivery();


// EuclidExtension
void EuclidExtension(int a, int b, int &x, int &y, int &d);


void TestEuclidExtension();


/*
	字符相同,但字符顺序不同,如何找出:
		用素数代替不同的字符,测乘积是否相同
		之所以用素数,是保证如果乘积相同的字符串唯一!
*/


/*
	计算根号2:
		1.模仿手算过程
		2.最小二乘法?
*/
void GenHaoTwo(char *ans, int num);






/*
	给定一个字符串的集合,格式如:{aaa bbb ccc},{bbb ddd},{eee fff},{ggg},{ddd hhh}
	要求将其中交集不为空的集合合并,要求合并完成后的集合之间无交集,
	例如上例应输出{aaa bbb ccc ddd hhh},{eee fff},{ggg}。
		1.数据结构:用set存储每一个集合。用List存储所有集合?
		2.遍历过程:要O(N2)?
			从链表头开始:如果有交集,则将其删除,同时加入到第一个中
		是否有其它方法?
		1.可以考虑用bit表示不同的字符串:每个集合用一个不同的bit串表示
		2.同样是遍历!遍历所有的bit串,得到结果
*/




int FishCount();


/*
	一维坐标轴上有N个区段,求重合区段最长的两个区段	
*/
struct Range
{
	int id;
	double start;
	double end;
	Range():id(-1), start(0.0), end(0.0)
	{}


	Range(int _id, double _start, double _end):id(_id), start(_start), end(_end)
	{}
};
// 传入区间的数组,输出两个重合最大的区间,以及重合的长度
int MaxLengthRange(Range ranges[], int size, Range &r1, Range &r2);


bool RangeCmp(const Range &r1, const Range &r2);


double MinOfTwoDouble(double d1, double d2);


/*	
	超大数据相乘:用字符串代替
	1、2、5分硬币,组成一角,有多少种组合:深搜,有序
*/
// 剪枝:当前必须比上一步小;剩余必须比最小的大
int CoinComposeNumber(int arr[], int size, int ans[], int step, int remain);


void TestCoinComposeNumber();


void MultiNumber(int *arr, int *ans, int size);




// 二叉查找树节点
struct TreeNode2
{
	int num;
	TreeNode2 *left;
	TreeNode2 *right;
	TreeNode2 *next;
	TreeNode2 *parent;


	TreeNode2(int _num, TreeNode2 *_left = 0, TreeNode2 *_right = 0, 
		TreeNode2 *_next = 0, TreeNode2 *_parent = 0) 
		: num(_num), left(_left), right(_right), next(_next), parent(_parent){}


};


/*
	对于一颗完全二叉树,要求给所有节点加上一个pNext指针,指向同一层的相邻节点;
	如果当前节点已经是该层的最后一个节点,则将pNext指针指向NULL;
		1.如果是左节点,找到其父节点的右孩子:即其兄弟节点
		2.如果是右节点,找到其叔叔节点的左孩子


	2.将树按照层序遍历放入队列中:准备两个队列,一个用于遍历,一个用于存储
		并在每一层设置标记位
*/
void FindNextNodePtr(TreeNode2 *root);


// 对于左子树,只需要parent
void FindNextNodePtrHelp(TreeNode2 *root, TreeNode2 *cur);


TreeNode2 *FindFirstLeftParent(TreeNode2 *root, TreeNode2 *cur, int &level);


// 通过队列实现
void FindNextNodePtr2(TreeNode2 *root);


/*
	在已经排好序的数组中寻找最接近M的数的组合 
*/
void ClosestToMOfArr(int *arr, int size, int M, bool *curMap, int cur, int step, int remain, 
	bool *bestMap, int best);


template<typename T>
void CopyArr(T *dest, T *src, int size);




// 相邻数的最大间隔
int MaxSubOfArr(int *arr, int size);


/*
	五笔的编码范围是a ~ y的25个字母,从1位到4位的编码,如果我们把五笔的编码按字典序
	排序,形成一个数组如下:a, aa, aaa, aaaa, aaab, aaac, … …, b,ba, baa, 
	baaa, baab, baac … …, yyyw, yyyx, yyyy.其中a的Index为0,aa的Index为1,
	aaa的Index为2,以此类推。
	1)编写一个函数,输入是任意一个编码,比如baca,输出这个编码对应的Index;
	2)编写一个函数,输入是任意一个Index,比如12345,输出这个Index对应的编码。


	1.25
*/
int CodeToIndex(char *str);


/*
	组合数的实现
*/
void GetMNumberFromArr(int *arr, int size, bool *map, int M, int step);


void PrintIntArrWithBool(int *arr, int size, bool *map);


void TestGetMNumberFromArr();


void GetZuHe(int *arr, int size);


#endif 


#include "MS_6.h"

void TestMS_6()
{
	//cout << "MS_6" << endl;
	//TestEggsInBasket();
	//TestMachineDelivery();
	//TestEuclidExtension();
	//FishCount();
	//TestCoinComposeNumber();
	TestGetMNumberFromArr();
}

int Scan(const char *text, const  char *name)
{
	assert(text && name);	
	char *ptr = const_cast<char *>(name);
	char *start = const_cast<char *>(text);
	int len = strlen(name);
	int pos = 0;

	// 从头遍历text,朴素匹配
	while (*text && *ptr)
	{
		if (*text == *ptr || *ptr == '?')
		{
			++text;
			++ptr;
		}
		else if (*ptr == '*')
		{
			++ptr;
			// *可以略过0个或多个字母,可以认为是一个递归过程
			if (Scan(text, ptr) != -1)
			{
				return pos;
			}
			else
			{
				// 重新开始匹配
				ptr = const_cast<char *>(name);
				pos = (text - start);
			}
		}
		else 
		{ // 两者不匹配
			ptr = const_cast<char *>(name);
			pos = (text - start);
		}
	}
	if (name + len == ptr)
	{
		// 找到匹配位置
		return pos;
	}
	return -1;
}

// N:基数位
void BaseSort(int *arr, int size, int N)
{
	// 辅助数组
	int *tmp = new int[size];
	int *count = new int [10];
	for (int i = 0; i < N; ++i)
	{
		// 对第i位进行排序
	}

	delete []tmp;
	delete []count;
}

void EggsInBasket(int eggs, int *ans, int basket, int index, int remain)
{
	if (index == basket)
	{
		if (remain == 0)
		{
			// 打印结果
			PrintIntArr(ans, basket);
		}
	}
	else
	{
		// 取遍每一个可能的结果:当前remain,剩下basket-index个篮子
		for (int i = remain - (basket - index) + 1; i > 0; --i)
		{
			// 1.必须小于前面的一个
			if (index != 0 && i > ans[index - 1])
			{
				continue;
			}
			// 2.保证剩余的eggs能保证后面至少一个
			//if (remain < basket - index)
			//{
			//	continue;
			//}
			ans[index] = i;
			// 回溯
			EggsInBasket(eggs, ans, basket, index + 1, remain - i);
		}
	}
}

void PrintIntArr(int *arr, int size)
{
	assert(arr);
	for (int i = 0; i < size; ++i)
	{
		cout << arr[i] << " ";
	}
	cout << endl;
}

void TestEggsInBasket()
{
	int arr[100];
	EggsInBasket(9, arr, 5, 0, 9);
}


int MachineDelivery(int *R, int *O, bool *map, int size, int remain, int *ans, int step)
{
	if (step == size)
	{
		PrintIntArr(ans, size);
		return 1;
	}
	else
	{		
		bool isOK = false;
		// 从未被分配的任务中挑选一个
		for (int i = 0; i < size; ++i)
		{ // 已经被执行过或者无法满足要求! 
			if (map[i] || remain < R[i])
			{
				continue;
			}
			// 将当前任务做为下一个要执行的任务
			map[i] = true;
			ans[step] = i;
			isOK = true;
			return MachineDelivery(R, O, map, size, remain - O[i], ans, step + 1);
		}
		if (!isOK)
		{ // 如果上一步没有结果,返回0
			return 0;
		}
	}
}

void TestMachineDelivery()
{
	int R[100] = {10, 8};
	int O[100] = {5, 6};
	bool map[100] = {false};
	int ans[100] = {-1};
	cout << "Count: "  << MachineDelivery(R, O, map, 2, 14, ans, 0) << endl;
}

void EuclidExtension(int a, int b, int &x, int &y, int &d)
{
	if (b == 0)
	{
		x = 1;
		y = 0;
		d = a;
	}
	else
	{		
		EuclidExtension(b, a % b, x, y, d);
		int tmp = x - (a / b) * y;
		y = x;
		x = tmp;
	}
}

void TestEuclidExtension()
{
	int x = 1;
	int y = 0; 
	int d = 0;
	EuclidExtension(25, 11, x, y, d);
}

void GenHaoTwo(char *ans, int num)
{
	// 最小二乘法.double 的精度无法满足条件!除非自己实现一个大double相乘
}


int FishCount()
{
	//int total = 1;
	//int count = 5;
	//while (count--)
	//{
	//	total *= 5;
	//	++total;
	//}
	//cout << total << endl;

	//count = 5;
	//while (count--)
	//{
	//	--total;
	//	total /= 5;
	//}
	//cout << total << endl;
	//return total;

	// a将fish分成5份后,b处理剩下的4/5
	return -1;
}

int MaxLengthRange(Range ranges[], int size, Range &r1, Range &r2)
{
	// 1. 排序 O(nlogn)
	sort(ranges, ranges + size, RangeCmp);
	// 2. 遍历
	double max = 0.0;
	for (int i = 0; i < size; ++i)
	{
		double end = ranges[i].end;
		// 找到start位置比i的end小的Range O(N2)
		for (int j = 0; j < size; ++j)
		{
			if (ranges[j].start <= end)
			{
				// 计算重合区间
				double minStart = MinOfTwoDouble(ranges[i].start, ranges[j].start);
				double minEnd = MinOfTwoDouble(ranges[i].end, ranges[j].end);
				double length = minEnd - minStart;
				if (length > max)
				{
					max = length;
					r1 = ranges[i];
					r2 = ranges[j];
				}
			}
		}
	}
	return max;
}

bool RangeCmp(const Range &r1, const Range &r2)
{
	return (r1.start <= r2.start);
}

double MinOfTwoDouble(double d1, double d2)
{
	return (d1 >= d2 ? d1 : d2);
}

int CoinComposeNumber(int arr[], int size, int ans[], int step, int remain)
{
	if (remain == 0)
	{
		PrintIntArr(ans, step);
		return 1;
	}
	else
	{
		int total = 0;
		// 将arr中的硬币挨着试
		for (int i = 0; i < size; ++i)
		{
			// 剪枝:当前必须比上一步小;剩余必须比最小的大
			if (step != 0 && arr[i] > ans[step - 1])
			{
				continue;
			}
			if (remain >= arr[i])
			{
				ans[step] = arr[i];
				total += CoinComposeNumber(arr, size, ans, step + 1, remain - arr[i]);
			}
		}
		return total;
	}
	//return 0;
}

void TestCoinComposeNumber()
{
	int arr[] = {5, 3, 2};
	int ans[100];
	cout << "total : " << CoinComposeNumber(arr, 3, ans, 0, 12) << endl;
}

void MultiNumber(int *arr, int *ans, int size)
{
	int left = 1;
	int right = 1;
	for (int i = 0; i < size; ++i)
	{
		ans[i] = 1;
	}
	for (int i = 0; i < size; ++i)
	{
		ans[i] *= left;
		ans[size - i - 1] *= right;
		left *= arr[i];
		right *= arr[size - i - 1];
	}
}


void FindNextNodePtr(TreeNode2 *root)
{
	// 保留父节点和祖父节点
	// 1.判断树是不是完全树

	// 2.
	// 左子树
	FindNextNodePtrHelp(root->left, root);
	// 右子树
	FindNextNodePtrHelp(root->right, root);
	// root本身
	root->next = NULL;
}

void FindNextNodePtrHelp(TreeNode2 *root, TreeNode2 *cur)
{
	if (!cur)
	{
		return;
	}
	FindNextNodePtrHelp(root, cur->left);
	FindNextNodePtrHelp(root, cur->right);

	// 寻找第一个节点,使得cur是其左孩子
	int level = 0;
	TreeNode2 *parent = FindFirstLeftParent(root, cur, level);
	if (parent)
	{
		parent = parent->right;
		--level;
		while (level--)
		{
			parent = parent->left;
		}
		cur->next = parent;
	}
	else
	{
		cur->next = NULL;
	}
}

TreeNode2 *FindFirstLeftParent(TreeNode2 *root, TreeNode2 *cur, int &level)
{
	// 
	level = 0;
	while (cur && cur->parent && cur == cur->parent->right)
	{
		cur = cur->parent;
		++level;
	}	
	return cur;
}

void FindNextNodePtr2(TreeNode2 *root)
{
	// 构造一个空TreeNode2,作为标记
	TreeNode2 *nullNode = new TreeNode2(-1, 0, 0, 0, 0);
	// 准备两个队列
	assert(root);
	// 用于遍历
	queue<TreeNode2 *> queueIter;
	// 用于存储
	queue<TreeNode2 *> queueStore;
	queueIter.push(root);
	queueIter.push(nullNode);
	queueStore.push(root);
	queueStore.push(nullNode);
	while (!queueIter.empty())
	{
		TreeNode2 *node = queueIter.front();
		queueIter.pop();
		if (node == NULL)
		{ // 如果有为空的,说明已经遍历完了,或者保证放入队列的一定不为空
			break;
		}
		// 如果是结束位置,则加入store中
		if (node->num == -1)
		{
			queueStore.push(nullNode);
		}
		else
		{
			// 将子树放入队列
			if (node->left)
			{
				queueIter.push(node->left);
				queueStore.push(node->left);
			}
			if (node->right)
			{
				queueIter.push(node->right);
				queueStore.push(node->right);
			}
		}
	}
	// 遍历queueStore队列,设置next
	TreeNode2 *prev = NULL;
	while (!queueStore.empty())
	{
		TreeNode2 *node = queueStore.front();
		queueStore.pop();
		if (!prev)
		{
			continue;
		}
		// 开始设置
		if (node->num == -1)
		{			
			prev->next = NULL;
			
			continue;
		}
		else
		{
			prev->next = node;	
		}		
	}	

	delete nullNode;
}

void ClosestToMOfArr(int *arr, int size, int M, bool *curMap, int cur, int step, int remain,
	bool *bestMap, int best)
{
	// 每做一步都要检查
	if (step == size)
	{
		if (abs(M - cur) < abs(M - best))
		{
			best = cur;
			CopyArr<bool>(bestMap, curMap, size);
		}
	}
	else
	{
		// 如果cur<M,将step放入
		if (cur < M)
		{
			curMap[step] = true;
			ClosestToMOfArr(arr, size, M, curMap, cur + arr[step], step + 1, 
				remain - arr[step], bestMap, best);
		}
		// 如果剩余的可能是解
		else 
		{
			curMap[step] = false;
			ClosestToMOfArr(arr, size, M, curMap, cur, step + 1, 
				remain - arr[step], bestMap, best);
		}
	}
}

template<typename T>
void CopyArr(T *dest, T *src, int size)
{
	assert(dest && src);
	for (int i = 0; i < size; ++i)
	{
		dest[i] = src[i];
	}
}

int MaxSubOfArr(int *arr, int size)
{
	// 1.最大值、最小值
	int min = arr[0];
	int max = arr[0];
	for (int i = 1; i < size; ++i)
	{
		if (arr[i] > max)
		{
			max = arr[i];
		}
		if (arr[i] < min)
		{
			min = arr[i];
		}
	}
	int range = (max - min) / (size - 1);
	if (range * (size - 1) != max - min)
	{
		++range;
	}

	// 假设size最大100
	int a[100];
	int b[100];
	// 初始化a b
	for (int i = 0; i < size - 1; ++i)
	{
		a[i] = i * range;
		b[i] = a[i] + range;
	}
	bool flag[100] = {false};
	// 构造N-1个桶
	for (int i = 0; i < size; ++i)
	{
		// arr[i]属于哪个桶, 向下取整
		int index = (arr[i] - min) / range;
		if (!flag[index])
		{
			flag[index] = true;
			a[index] = arr[i];
			b[index] = arr[i];
		}
		else
		{
			if (arr[i] > b[index])
			{
				b[index] = arr[i];
			}
			if (arr[i] < a[index])
			{
				a[index] = arr[i];
			}
		}
	}
	// 遍历结果
	int length = 0;
	for (int i = 1; i < size - 1; ++i)
	{
		int tmp = a[i] - b[i - 1];
		if (tmp > length)
		{
			length = tmp;
		}
	}
	return length;
}

int CodeToIndex(char *str)
{
	int index = 0;
	while (*str)
	{
		
	}
	return -1;
}

void GetMNumberFromArr(int *arr, int size, bool *map, int M, int step)
{
	if (M == 0)
	{
		PrintIntArrWithBool(arr, size, map);
		return;
	}
	for (int i = step; i < size; ++i)
	{
		if (!map[i])
		{
			map[i] = true;
			GetMNumberFromArr(arr, size, map, M - 1, i + 1);
			map[i] = false;
		}
	}
}

void PrintIntArrWithBool(int *arr, int size, bool *map)
{
	for (int i = 0; i < size; ++i)
	{
		if (map[i])
		{
			cout << arr[i] << " ";
		}
	}
	cout << endl;
}

void TestGetMNumberFromArr()
{
	int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
	//bool map[5] = {false};
	//GetMNumberFromArr(arr, 5, map, 3, 0);
	GetZuHe(arr, 9);
}

void GetZuHe(int *arr, int size)
{
	bool map[10] = {false};
	for(int i = 1; i <= size; ++i)
	{
		GetMNumberFromArr(arr, size, map, i, 0);
	}
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值