假币问题
时间复杂度为O(logn)
#include <iostream>
using namespace std;
int weightSum(int *coins, int begin, int end);
int findBadCoinIterate(int *coins, int length, int &model);
int findBadCoinRecursion(int *coins, int begin, int end, int &model);
void findBadCoinTest();
int main() {
findBadCoinTest();
return 0;
}
int weightSum(int *coins, int begin, int end) {
int sum = 0;
for(int i = begin;i <= end;i++) {
sum += coins[i];
}
return sum;
}
//递归实现
int findBadCoinRecursion(int *coins, int begin, int end, int &model) {
int n = end - begin + 1;
if(n == 1) {
return begin;//因为只剩一个硬币了
}
else if(n == 2) {
return coins[begin] != model ? begin : end;//两个之中只有一个是假币,注意model肯定是真币,因为在n >= 3的时候求过了
}
int midl = n / 3 - 1;//A堆的最后一个
int midr = 2 * (n / 3) + n % 3;//B堆的第一个
int sumA = weightSum(coins, begin, midl + begin);//称重
int sumB = weightSum(coins, midr + begin, end);
if(sumA == sumB) {
model = coins[begin];//找到真币,假币在中间那堆
return findBadCoinRecursion(coins, midl + begin + 1, midr + begin - 1, model);
}
else {
model = coins[midl + begin + 1];//真币在中间那堆
int num = midl + 1;//A,B堆的硬币个数,A,B的硬币个数相等,A堆的数量是num = midl + begin - begin + 1 = midl + 1
if(sumA == num * model) {
return findBadCoinRecursion(coins, midr + begin, end, model);//假币在B堆
}
else {
return findBadCoinRecursion(coins, begin, midl + begin, model);//假币在A堆
}
}
}
//迭代实现
int findBadCoinIterate(int *coins, int length, int &model) {
int begin = 0;
int end = length - 1;
while(begin <= end) {
int n = end - begin + 1;
if(n == 1) {
return begin;
}
else if(n == 2) {
return coins[begin] != model ? begin : end;
}
int midl = n / 3 - 1;
int midr = 2 * (n / 3) + n % 3;
int sumA = weightSum(coins, begin, midl + begin);
int sumB = weightSum(coins, midr + begin, end);
if(sumA == sumB) {
model = coins[begin];//找到真币
begin = midl + begin + 1;//假币在中间那堆,缩小范围
end = midr + begin - 1;
}
else {
model = coins[midl + begin + 1];
int nAB = midl + 1;
if(sumA == nAB * model) {
begin = midr + begin;//假币在B堆,缩小范围
}
else {
end = midl + begin;//假币在A堆,缩小范围
}
}
}
return -1;
}
//测试
void findBadCoinTest() {
int contin = 1;
do {
system("cls");
int n = 0;
cout << "请输入硬币数量n(n > 3):";
cin >> n;
if(n < 3) {
cout << "你输入的硬币数量太少了!" << endl;
continue;
}
int *coins = new int[n];
cout << "请输入硬币的重量:";
for(int i = 0;i < n;i++) {
cin >> coins[i];
}
int model = -1;
int index = -1;
cout << "--------递归结果--------\n" << endl;
model = -1;
index = findBadCoinRecursion(coins, 0, n - 1, model);
if(coins[index] > model) {
cout << "第" << index + 1 << "个硬币是假的,比其他硬币重了!" << endl;
}
else if(coins[index] < model) {
cout << "第" << index + 1 << "个硬币是假的,比其他硬币轻了!" << endl;
}
else {
cout << "没有假币!" << endl;
}
cout << "\n--------迭代结果--------" << endl;
model = -1;
index = findBadCoinIterate(coins, n, model);
if(coins[index] > model) {
cout << "第" << index + 1 << "个硬币是假的,比其他硬币重了!" << endl;
}
else if(coins[index] < model) {
cout << "第" << index + 1 << "个硬币是假的,比其他硬币轻了!" << endl;
}
else {
cout << "没有假币!" << endl;
}
delete []coins;
cout << "继续检测输入1,退出输入0:";
cin >> contin;
} while (contin == 1);
cout << "欢迎再次检测!" << endl;
}
def weight_sum(coins, begin, end):
return sum(coins[begin:end+1])
def find_bad_coin_recursion(coins, begin, end, model):
n = end - begin + 1
if n == 1:
return begin
elif n == 2:
return begin if coins[begin] != model else end
midl = n // 3 - 1
midr = 2 * (n // 3) + n % 3
sumA = weight_sum(coins, begin, midl + begin)
sumB = weight_sum(coins, midr + begin, end)
if sumA == sumB:
model = coins[begin]
return find_bad_coin_recursion(coins, midl + begin + 1, midr + begin - 1, model)
else:
model = coins[midl + begin + 1]
num = midl + 1
if sumA == num * model:
return find_bad_coin_recursion(coins, midr + begin, end, model)
else:
return find_bad_coin_recursion(coins, begin, midl + begin, model)
def find_bad_coin_iterate(coins, model):
begin, end = 0, len(coins) - 1
while begin <= end:
n = end - begin + 1
if n == 1:
return begin
elif n == 2:
return begin if coins[begin] != model else end
midl = n // 3 - 1
midr = 2 * (n // 3) + n % 3
sumA = weight_sum(coins, begin, midl + begin)
sumB = weight_sum(coins, midr + begin, end)
if sumA == sumB:
model = coins[begin]
begin, end = midl + begin + 1, midr + begin - 1
else:
model = coins[midl + begin + 1]
nAB = midl + 1
if sumA == nAB * model:
begin = midr + begin
else:
end = midl + begin
return -1
def find_bad_coin_test():
contin = 1
while contin == 1:
n = int(input("Enter the number of coins (n > 3): "))
if n < 3:
print("You entered too few coins!")
continue
coins = [int(input("Enter weight of coin {}: ".format(i + 1))) for i in range(n)]
model = -1
print("--------Recursive Result--------\n")
model = -1
index = find_bad_coin_recursion(coins, 0, n - 1, model)
if coins[index] > model:
print("Coin {} is fake and heavier than the others!".format(index + 1))
elif coins[index] < model:
print("Coin {} is fake and lighter than the others!".format(index + 1))
else:
print("No fake coin!")
print("\n--------Iterative Result--------")
model = -1
index = find_bad_coin_iterate(coins, model)
if coins[index] > model:
print("Coin {} is fake and heavier than the others!".format(index + 1))
elif coins[index] < model:
print("Coin {} is fake and lighter than the others!".format(index + 1))
else:
print("No fake coin!")
contin = int(input("Continue testing? Enter 1 for yes, 0 for no: "))
print("Welcome to test again!")
if __name__ == "__main__":
find_bad_coin_test()
2第K大数
AB数组,升降序,元素不同,找出2n个数中第n大的数
O( min ( log M, log N ))
def func2(num1,num2,k):
if not num1:
return num2[k-1]
if not num2:
return num1[k-1]
if k == 1:
return min(num1[0], num2[0])
k1 = k // 2
k2 = k - k1
if num1[k1-1] > num2[k2-1]:
return func2(num1, num2[k2:], k-k2)
else:
return func2(num1[k1:], num2, k-k1)
print(func2([4,5,6],[1,2,3],4))
def func2(num1, num2, k):
if not num1:
return num2[-k]
if not num2:
return num1[-k]
if k == 1:
return max(num1[-1], num2[-1])
k1 = k // 2
k2 = k - k1
if num1[-k1] < num2[-k2]:
return func2(num1, num2[:-k2], k - k2)
else:
return func2(num1[:-k1], num2, k - k1)
print(func2([6,5,4], [3,2,1], 4))
3概率算法
求定积分、sin、cos、多项式、P236T7-3
定积分
时间复杂度O(n)
import random
def f(x):
return x * x
def Darts(n, a, b, d):
k = 0
for i in range(n):
x = (b - a) * random.random() + a # Generate a random number in [a, b)
y = d * random.random()
if y <= f(x):
k += 1
return d * (b - a) * k / n
# Example usage:
n = 1000 # Replace with your actual value for n
a = 1.0 # Replace with your actual value for a
b = 2.0 # Replace with your actual value for b
d = 3.0 # Replace with your actual value for d
result = Darts(n, a, b, d)
print("Result:", result)
double Darts(int n,double a,double b,double d)
{
static RandomNumber dart;
int k = 0;
for(int i=0; i<n; i++)
{
double x = (b-a)*dart.fRandom() + a;//产生[a,b)之间的随机数
double y = d * dart.fRandom();
if(y<=f(x))
{
k++;
}
}
return d*(b-a)*k/n;
}
double f(double x)
{
return x*x;
}
洗牌
在n个不同的数中随机取出不重复的m个数
三种洗牌算法shuffle-CSDN博客
时间复杂度O(n)
void Knuth_Durstenfeld_Shuffle(vector<int>& arr)
{
for (int i = arr.size() - 1; i >= 0; --i)
{
srand((unsigned)time(NULL)); // 每次循环都重新设置随机数种子
swap(arr[rand() % (i + 1)], arr[i]); // 交换当前元素与随机选择的元素
}
}
答案时间复杂度可以表示为 O(n)
import random
def floyd(n, m, s):
rnd = random.Random()
y = 0
while y < m:
for j in range(n - m + 1, n + 1):
u = rnd.random()
k = 1 + int(j * u)
if s[k] == 0:
s[k] += 1
y += 1
elif s[j] == 0:
s[j] += 1
y += 1
void Floyd(int n, int m, int s[]){
RandomNumber rnd;
int y = 0;
while(y < m){
for(int j=n-m+1;j <=n;j++){
double u=rnd.fRandom();
int k =1+j*u;
if(s[k] == 0) {
s[k ]++;
y++;}
else if(s[j]==0){
s[j]++;
y++;
}
}
}
}
4时间复杂度
三种方法求递归算法的时间复杂度(递推,master定理,递归树)_递归时间复杂度-CSDN博客
线性递推
特征方程和递归算法
【数列】特征方程与特征根
数列特征根相等怎么办? - 知乎用户的回答 - 知乎 https://www.zhihu.com/question/518854540/answer/2555589396
迭代法
等比数列: Sn=a1 (1-q^n)/ (1-q)
等差数列: Sn=(a1+an)*n/2
主定理
1
2
5
2-7多项式乘积
2-9空间合并算法
def merge(a, left, mid, right):
i = left
j = mid + 1
# 如果左半部分的最大值小于右半部分的最小值,说明已经有序,无需合并
if a[mid] <= a[j]:
return
while i <= mid and j <= right:
if a[i] <= a[j]:
i += 1
else:
value = a[j]
index = j
# 将右半部分的元素插入到左半部分的适当位置
while index > i:
a[index] = a[index - 1]
index -= 1
a[i] = value
i += 1
mid += 1
j += 1
# 示例
arr = [1, 2, 4, 5, 7, 8, 10, 3, 6, 9]
left = 0
mid = 6
right = len(arr) - 1
# 合并左右两部分
merge(arr, left, mid, right)
print("排序后的数组:", arr)
6
3-1 最长单调递增子序列。
设计一个O(n^2)时间的算法,找出由n个数组成的序列的最长单调递增子序列。
def longest_increasing_subsequence(arr):
n = len(arr)
if n == 0:
return 0
# 初始化dp数组,每个元素至少可以形成长度为1的递增子序列
dp = [1] * n
# 从第二个元素开始遍历
for i in range(1, n):
# 对于每个元素,从第一个元素到当前元素,检查是否能形成递增子序列
for j in range(i):
if arr[i] > arr[j]:
# 如果可以形成递增子序列,更新dp数组
dp[i] = max(dp[i], dp[j] + 1)
# 返回dp数组中的最大值,即最长递增子序列的长度
return max(dp)
# 示例
sequence = [10, 22, 9, 33, 21, 50, 41, 60, 80]
result = longest_increasing_subsequence(sequence)
print("最长递增子序列的长度为:", result)
3-4 二维背包问题
给定n种物品和一背包。物品i的重量是w,,体积是b;,其价值为v,背包的容量为c,容积为d。问应如何选择装入背包中的物品,使得装入背包中物品的总价值最大?在选择装入背包的物品时,对每种物品i只有两种选择,即装入背包或不装入背包。不能将物品i装入背包多次,也不能只装入部分的物品 i。试设计一个解此问题的动态规划算法,并分析算法的计算复杂性。
def multi_dimensional_knapsack(weights, volumes, values, capacity_w, capacity_b):
n = len(weights)
# 创建一个三维数组来存储最优解
dp = [[[0] * (capacity_b + 1) for _ in range(capacity_w + 1)] for _ in range(n + 1)]
for i in range(1, n + 1):
for w in range(capacity_w + 1):
for b in range(capacity_b + 1):
# 如果当前物品重量和体积不超过背包容量
if weights[i-1] <= w and volumes[i-1] <= b:
# 考虑将当前物品放入背包,更新最优解
dp[i][w][b] = max(dp[i-1][w][b], dp[i-1][w-weights[i-1]][b-volumes[i-1]] + values[i-1])
else:
# 如果当前物品不能放入背包,继承上一行的最优解
dp[i][w][b] = dp[i-1][w][b]
return dp[n][capacity_w][capacity_b]
# 示例
weights = [2, 1, 3]
volumes = [1, 2, 3]
values = [8, 7, 6]
capacity_w = 3
capacity_b = 3
result = multi_dimensional_knapsack(weights, volumes, values, capacity_w, capacity_b)
print("最大价值:", result)
7
Fibonacci序列的哈夫曼编码。
字符a~h出现的频率恰好是前8个 Fibonacci 数,它们的哈夫曼编码是什么?将结果推广到n个字符的频率恰好是前n个 Fibonacci 数的情形。
class Node:
def __init__(self, char=None, freq=0):
self.char = char
self.freq = freq
self.left = None
self.right = None
def fibonacci_numbers(n):
fib_sequence = [0, 1]
while len(fib_sequence) < n:
fib_sequence.append(fib_sequence[-1] + fib_sequence[-2])
return fib_sequence
def build_huffman_tree(characters, frequencies):
nodes = [Node(char=char, freq=freq) for char, freq in zip(characters, frequencies)]
while len(nodes) > 1:
# 排序节点列表,根据频率从小到大
nodes = sorted(nodes, key=lambda x: x.freq)
# 取出两个最小频率的节点
left = nodes.pop(0)
right = nodes.pop(0)
# 创建新节点,作为左右子节点的父节点,频率为左右子节点频率之和
parent = Node(freq=left.freq + right.freq)
parent.left = left
parent.right = right
# 将新节点加入节点列表
nodes.append(parent)
# 返回哈夫曼树的根节点
return nodes[0]
def generate_huffman_codes(node, current_code="", code_dict=None):
if code_dict is None:
code_dict = {}
if node.char:
code_dict[node.char] = current_code
if node.left:
generate_huffman_codes(node.left, current_code + "0", code_dict)
if node.right:
generate_huffman_codes(node.right, current_code + "1", code_dict)
return code_dict
def main():
characters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
frequencies = fibonacci_numbers(8)
huffman_tree = build_huffman_tree(characters, frequencies)
huffman_codes = generate_huffman_codes(huffman_tree)
for char, code in sorted(huffman_codes.items()):
print(f"Character: {char}, Huffman Code: {code}")
if __name__ == "__main__":
main()
8
5-1子集和问题。
问题描述:子集和问题的一个实例为<S, >。其中,S={X1,X2,…,Xn}是一个正整数的集合,c是一个正整数。子集和问题判定是否存在S的一个子集S1,使得∑x=c。试设计一个解子集和问题的回溯法。\
def backtrack(t):
global n, c, r, cw, bestw, x, bestx, w
if t > n:
for i in range(1, n + 1):
bestx[i] = x[i]
if bestw == c:
return True
else:
return False
r -= w[t]
if cw + w[t] <= c:
x[t] = 1
cw += w[t]
if backtrack(t + 1):
return True
cw -= w[t]
if cw + r >= bestw:
x[t] = 0
if backtrack(t + 1):
return True
r += w[t]
return False
# Example usage:
n = 5 # Replace with your actual values
c = 10 # Replace with your actual values
r = sum(w) # Assuming w is defined elsewhere in your code
cw = 0
bestw = float('-inf')
x = [0] * (n + 1)
bestx = [0] * (n + 1)
w = [2, 3, 4, 5, 6] # Replace with your actual values
if backtrack(1):
print("Solution found:")
print("Best weight:", bestw)
print("Selected items:", bestx[1:])
else:
print("No solution found.")
bool backtrack(int t) {
if (t > n) {
for (int i = 1; i <= n; i++)
bestx[i] = x[i];
if (bestw == c)
return true;
else
return false;
}
r -= w[t];
if (cw + w[t] <= c) {
x[t] = 1;
cw += w[t];
if (backtrack(t + 1))
return true;
cw -= w[t];
}
if (cw + r >= bestw) {
x[t] = 0;
if (backtrack(t + 1))
return true;
}
r += w[t];
return false;
}
5-3最小重量机器设计问题。
问题描述:设某一机器由n个部件组成,每种部件都可以从m个不同的供应商处购得。设wij是从供应商j处购得的部件i的重量,cij是相应的价格。试设计一个算法,给出总价格不超过c的最小重量机器设计。
# 设 w[i][j] 是从供应商j处购得的部件 i 的重量, c[i][j] 是相应的价格。
# 限定:价格不超过p 重量尽可能小
n = 3 # 零件数量
m = 2 # 供应商数量
p = 60 # 不应超过的价格
w = [[12, 15], [23, 24], [78, 70]] # 供应商j处购得的部件 i 的重量
c = [[8, 6], [13, 9], [14, 25]] # 相应的价格
min_weight = 10000
bast_choose = [None]*3
cur_choose = [None]*10
cur_weight = 0
cur_price = 0
def backtrack(t):
# 此处的t代表每一次遍历i供应商的零件
global cur_weight, cur_price, cur_choose, min_weight, p, w, c
if t == n:
# 遍历到叶子结点
if cur_weight < min_weight:
min_weight = cur_weight
for j in range(n):
bast_choose[j] = cur_choose[j] + 1
return
else:
for i in range(m): # 遍历供应商
cur_choose[t] = i
cur_weight += w[t][i]
cur_price += c[t][i]
if cur_weight < min_weight and cur_price <= p:
# 该供应商的重量小于局部最优解 同时价格满足要求 则遍历其子树
backtrack(t+1)
cur_weight -= w[t][i]
cur_price -= c[t][i]
cur_choose[t] = 0
def main():
backtrack(0)
print('最小的重量是:%d'%min_weight)
print('最佳选择是:',bast_choose)
if __name__ == '__main__':
main()
9时间复杂度
查找
常见的查找算法有很多种,它们的时间复杂度不同。以下是一些常见的查找算法及其时间复杂度的比较:
顺序查找 (Sequential Search):
- 时间复杂度:O(n)
- 算法简单,适用于小规模数据。
二分查找 (Binary Search):
- 仅适用于有序数组。
- 时间复杂度:O(log n)
- 比顺序查找效率高,但要求数据有序。
哈希查找 (Hash Search):
- 平均情况下,时间复杂度为O(1)。但在最坏情况下可能为O(n)。
- 需要合适的哈希函数,并处理哈希冲突。
树结构查找(二叉搜索树、平衡二叉搜索树、B树、B+树):
- 二叉搜索树 (Binary Search Tree):
- 平均时间复杂度:O(log n)
- 可能出现最差情况O(n),例如树不平衡。
- 平衡二叉搜索树 (AVL Tree):
- 时间复杂度:O(log n)
- 保持树的平衡,提高了查找效率。
- B树和B+树:
- 通常用于数据库索引,对磁盘存储友好,减少磁盘I/O。
- 时间复杂度:O(log n)
跳表 (Skip List):
- 在有序链表的基础上加入多级索引,提高查询效率。
- 平均时间复杂度:O(log n)
这些算法的选择取决于具体的应用场景和数据特征。例如,对于有序数据,二分查找是一个不错的选择;对于哈希查找,需要考虑哈希函数的设计和处理冲突的方法。