定义:
一个先自顶向下,再自底向上的过程,一共分为三步。
1. 分–将问题分解为规模更小的子问题。
2. 治–将这些规模更小的子问题逐个击破。
3.合–将已解决的子问题合并,最终得出“母”问题的解;
题目一:
假设某股票1号时价格为100,后面几天的价格如下,问在哪一天买入然后哪一天卖出收益最大?
100, 113, 110, 85, 105, 102, 86, 63, 81, 101, 94, 106, 101, 94, 106, 101, 79, 94, 90, 97
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test : MonoBehaviour {
private void Main() {
//股票价格,1号开始
int[] priceArray = { 100, 113, 110, 85, 105, 102, 86, 63, 81, 101, 94, 106, 101, 94, 106, 101, 79, 94, 90, 97 };
//每日盈亏 0 13 -3 -25 20 -3 -16 -23 18 20 -7 12 -5 -7 12 -5 -22 15 -4 7
int[] dayIncreaseArray = new int[priceArray.Length];
dayIncreaseArray[0] = 0;
for (int i = 1; i < dayIncreaseArray.Length; i++)
{
dayIncreaseArray[i] = priceArray[i] - priceArray[i - 1];
}
Data data = DivideAndConquerMethod(dayIncreaseArray);
Debug.Log(string.Format("在第{0}天买入,第{1}天卖出利润最大,总利润为{2}", data.StartIndex, data.EndIndex + 1, data.Profit));
}
/// <summary>
/// 买卖数据
/// </summary>
public class Data {
public Data(int start, int end, int profit) {
StartIndex = start;
EndIndex = end;
Profit = profit;
}
//买入的那天
public int StartIndex;
//卖出的那天
public int EndIndex;
//赚取的利润
public int Profit;
}
/// <summary>
/// 分治算法
/// </summary>
/// <param name="targetArray">股票每日盈亏</param>
private Data DivideAndConquerMethod(int[] targetArray) {
return DecompositionProblem(0, targetArray.Length - 1, targetArray);
}
/// <summary>
/// 分解问题
/// </summary>
private Data DecompositionProblem(int startIndex, int endIndex, int[] targetArray) {
if (startIndex == endIndex)
{
Data data = new Data(startIndex, endIndex, 0);
return data;
}
int midIndex = (startIndex + endIndex) / 2;
//第一种情况,买卖日都在左边
Data leftPart = DecompositionProblem(startIndex, midIndex, targetArray);
//第二种情况,买卖日都在右边边
Data rightPart = DecompositionProblem(midIndex + 1, endIndex, targetArray);
//第三种情况,买日在左边,卖日在右边
Data midPart = new Data(midIndex, midIndex, 0);
int leftTemp = targetArray[midIndex];
int leftTotal = targetArray[midIndex];
for (int i = midIndex - 1; i >= startIndex; i--)
{
leftTemp += targetArray[i];
if (leftTemp > leftTotal)
{
midPart.StartIndex = i;
leftTotal = leftTemp;
}
}
midPart.Profit = leftTotal;
int rightTemp = 0;
int rightTotal = 0;
for (int i = midIndex + 1; i <= endIndex; i++)
{
rightTemp += targetArray[i];
if (rightTemp > rightTotal)
{
midPart.EndIndex = i;
rightTotal = rightTemp;
}
}
midPart.Profit += rightTotal;
//判断三种情况种哪种利润最大
if (leftPart.Profit >= midPart.Profit && leftPart.Profit >= rightPart.Profit)
{
return leftPart;
}
else if (midPart.Profit >= rightPart.Profit)
{
return midPart;
}
else
{
return rightPart;
}
}
}
题目二:
在经典汉诺塔问题中,有 3 根柱子及 N 个不同大小的穿孔圆盘,盘子可以滑入任意一根柱子。一开始,所有盘子自上而下按升序依次套在第一根柱子上(即每一个盘子只能放在更大的盘子上面)。移动圆盘时受到以下限制:
(1) 每次只能移动一个盘子;
(2) 盘子只能从柱子顶端滑出移到下一根柱子;
(3) 盘子只能叠在比它大的盘子上。
请编写程序,用栈将所有盘子从第一根柱子移到最后一根柱子。
你需要原地修改栈。
示例1:
输入:A = [2, 1, 0], B = [], C = []
输出:C = [2, 1, 0]
示例2:
输入:A = [1, 0], B = [], C = []
输出:C = [1, 0]
using System.Collections.Generic;
using UnityEngine;
public class Test : MonoBehaviour {
private void Main() {
List<int> a = new List<int>() { 7, 6, 5, 4, 3, 2, 1 };
List<int> b = new List<int>();
List<int> c = new List<int>();
DivideAndConquerMethod(a, b, c);
foreach (var item in c)
{
print(item);
}
}
/// <summary>
/// 分治算法
/// </summary>
private void DivideAndConquerMethod(List<int> a, List<int> b, List<int> c) {
DecompositionProblem(a.Count, a, b, c);
}
/// <summary>
/// 分解问题
/// </summary>
private void DecompositionProblem(int n, List<int> a, List<int> b, List<int> c) {
if (n == 1)
{
c.Add(a[a.Count - 1]);
a.RemoveAt(a.Count - 1);
}
else
{
DecompositionProblem(n - 1, a, c, b);
c.Add(a[a.Count - 1]);
a.RemoveAt(a.Count - 1);
DecompositionProblem(n - 1, b, a, c);
}
}
}
题目三:
猜数字游戏的规则如下:
- 每轮游戏,我都会从 1 到 n 随机选择一个数字。 请你猜选出的是哪个数字。
using System.Collections.Generic;
using UnityEngine;
public class Test : MonoBehaviour {
//目标值
int target = 2;
private void Main() {
int result = DivideAndConquerMethod(100);
print(result);
}
/// <summary>
/// 分治算法
/// </summary>
/// <param name="n">个数</param>
/// <returns></returns>
private int DivideAndConquerMethod(int n) {
return DecompositionProblem(1, n);
}
/// <summary>
/// 分解问题
/// </summary>
/// <param name="left">最小可能值</param>
/// <param name="right">最大可能值</param>
/// <returns></returns>
private int DecompositionProblem(int left, int right) {
int mid = (right + left) / 2;
if (mid == target)
{
return mid;
}
else if (mid < target)
{
return DecompositionProblem(mid + 1, right);
}
else
{
return DecompositionProblem(left, mid - 1);
}
}
}