体系班第十四节

1给定一个字符串str,只由'X'和'.'两种字符构成
'X'表示墙,不能放灯,也不需要点亮;'.'表示居民点,可以放灯,需要点亮
如果灯放在i位置,可以让i-1,i和i+1三个位置被点亮
返回如果点亮str中所有需要点亮的位置,至少需要几盏灯

从左往右依次考虑是否放灯不放灯

若遍历到的点是x,则直接跳过

若遍历到的点是i,则先判断下一个什么情况:

下一个超范围,灯得在该处放,灯数加

下一个是x,灯得到该处放,灯加,然后i跳两格

下一个是.,灯数加,无论i+2是什么,情况都一样,之后i跳三格

#include <string>

using namespace std;

int minLight1(string road) {
    int i = 0;
    int light = 0;
    while (i < road.length()) {
        if (road[i] == 'X') {
            i++;
        } else {
            light++;
            if (i + 1 == road.length()) {
                break;
            } else {
                if (road[i + 1] == 'X') {
                    i = i + 2;
                } else {
                    i = i + 3;
                }
            }
        }
    }
    return light;
}

2一些项目要占用一个会议室宣讲,会议室不能同时容纳两个项目的宣讲,给你每一个项目开始的时间和结束的时间
你来安排宣讲的日程,要求会议室进行的宣讲的场次最多,返回最多的宣讲场次

策略:每次都选结束时间最早的

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class program {
public:
	int start;
	int end;
	program(int a,int b):start(a),end(b){}
};
//暴力法:每个会议都去尝试 arr表示还剩下多少会议
int process(vector<program>& arr, int done, int timeline)
{
	if (arr.empty())
		return done;
	int maxcount = done;
	for (int i = 0; i < arr.size(); i++)
	{
		if (arr[i].start >= timeline)
		{
			vector<program> next(arr);
			next.erase(next.begin() + i);
			maxcount = max(maxcount, process(next, done + 1, arr[i].end));
		}
		return maxcount;
	}
}
int bestArrange1(vector<program>& arr)
{
	if (arr.empty())
		return 0;
	return process(arr, 0, 0);
}
//贪心法:每次都选择结束时间最晚的会议
int bestArrange2(vector<program>& programs) {
	sort(programs.begin(), programs.end(), [](const program& a, const program& b) {
		return a.end < b.end;
		});

	int timeLine = 0;
	int result = 0;
	for (const program& program : programs) {
		if (timeLine <= program.start) {
			result++;
			timeLine = program.end;
		}
	}
	return result;
}

3一块金条切成两半,是需要花费和长度数值一样的铜板
比如长度为20的金条,不管怎么切都要花费20个铜板,一群人想整分整块金条,怎么分最省铜板? 
例如,给定数组{10,20,30},代表一共三个人,整块金条长度为60,金条要分成10,20,30三个部分。
如果先把长度60的金条分成10和50,花费60;再把长度50的金条分成20和30,花费50;一共花费110铜板
但如果先把长度60的金条分成30和30,花费60;再把长度30金条分成10和20,花费30;一共花费90铜板

哈夫曼编码问题:每次从小根堆里面弹出两个最小数,然后合并

#include <iostream>
#include <queue>
#include <vector>
using namespace std;
int lessMoney(vector<int>& arr)
{
	priority_queue<int, vector<int>, greater<int>> p;
	for (int i = 0; i < arr.size(); i++)
	{
		p.push(arr[i]);
	}
	int sum = 0, cur = 0;
	while (p.size() > 1)
	{
		cur = p.top(), p.pop();
		cur += p.top(), p.pop();
		sum += cur;
		p.push(cur);
	}
	return sum;
}
#include <vector>
#include <climits>
using namespace std;

int lessMoney1(vector<int>& arr) {
    if (arr.empty()) {
        return 0;
    }
    return process(arr, 0);
}

int process(vector<int>& arr, int pre) {
    if (arr.size() == 1) {
        return pre;
    }
    int ans = INT_MAX;
    for (int i = 0; i < arr.size(); i++) {
        for (int j = i + 1; j < arr.size(); j++) {
            vector<int> newArr = copyAndMergeTwo(arr, i, j);
            ans = min(ans, process(newArr, pre + arr[i] + arr[j]));
        }
    }
    return ans;
}

vector<int> copyAndMergeTwo(vector<int>& arr, int i, int j) {
    vector<int> ans;
    for (int arri = 0; arri < arr.size(); arri++) {
        if (arri != i && arri != j) {
            ans.push_back(arr[arri]);
        }
    }
    ans.push_back(arr[i] + arr[j]);
    return ans;
}

4

输入正数数组costs、正数数组profits、正数K和正数M

costs[i]表示i号项目的花费
profits[i]表示i号项目在扣除花费之后还能挣到的钱(利润)
K表示你只能串行的最多做k个项目
M表示你初始的资金
说明:每做完一个项目,马上获得的收益,可以支持你去做下一个项目,不能并行的做项目。
输出:最后获得的最大钱数

#include <vector>
#include <queue>
#include <functional>
using namespace std;
class program {
public:
	int p;//表示一个项目的利润
	int c;//表示一个项目的花费
	program(int a,int b):p(a),c(b){}
};
//按花费少的比较器建立小根堆
class mincost {
public:
	bool operator()(program a, program b)
	{
		return a.c > b.c;
	}
};
class maxprofit {
public:
	bool operator()(program a, program b)
	{
		return a.p < b.p;
	}
};
int findMaximizedCapital(int k, int w, vector<int>& profits, vector<int>& capital)
{
	priority_queue<program, vector<program>, mincost> minc;
	priority_queue<program, vector<program>, maxprofit> maxp;
	for (int i = 0; i < profits.size(); i++)
	{
		minc.push(program(profits[i],capital[i]));
	}
	for (int i = 0; i < k; i++)
	{
		while (!minc.empty() && minc.top().c <= w)
		{
			maxp.push(minc.top());
			minc.pop();
		}
		if (maxp.empty())
		{
			return w;
		}
		w += maxp.top(). p;
		maxp.pop();
	}
	return w;
}

 5 并查集的实现

功能:查找是否在一个集合,合并两个所在的集合,实现了o(1)的查找

#include <unordered_map>
#include <vector>
#include <stack>
using namespace std;

// 每个数据封装一个节点
template<typename V>
class node {
public:
    V value;
    node(V a) : value(a) {} // 使用成员初始化列表初始化成员变量
};

template <typename V>
class unionfind {
public:
    unordered_map<V, node<V>*> nodes;
    unordered_map<node<V>*, node<V>*> parents;
    unordered_map<node<V>*, int> sizeMap;

    unionfind(vector<V> arr) {
        for (V a : arr) {
            node<V>* cur = new node<V>(a);
            nodes[a] = cur;
            parents[cur] = cur;
            sizeMap[cur] = 1;
        }
    }

    // 查找过程的优化:把沿途节点都直接挂在代表节点下面
    node<V>* findfather(node<V>* cur) {
        stack<node<V>*> path;
        while (cur != parents[cur]) {
            path.push(cur);
            cur = parents[cur];
        }
        while (!path.empty()) {
            parents[path.top()] = cur;
            path.pop();
        }
        return cur;
    }

    bool issameset(V a, V b) {
        return findfather(nodes[a]) == findfather(nodes[b]);
    }

    void union(V a, V b) {
        node<V>* ahead = findfather(nodes[a]);
        node<V>* bhead = findfather(nodes[b]);
        if (ahead != bhead) {
            int asize = sizeMap[ahead]; // 使用sizeMap[ahead]
            int bsize = sizeMap[bhead]; // 使用sizeMap[bhead]
            node<V>* big = asize > bsize ? ahead : bhead;
            node<V>* small = big == ahead ? bhead : ahead;
            parents[small] = big;
            sizeMap[big] = asize + bsize;
            sizeMap.erase(small);
        }
    }

    int sets() {
        return sizeMap.size();
    }
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值