#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);
}
}