刷牛客编程题,变红名大佬(一)(水仙花数、删除链表倒数第n个节点、动态规划题)

目前还是小黄,加油刷,努力变成红名大佬                                  (2019.4.20)

 

题目——水仙花数

思路

字符串处理+遍历

实现代码:

#include<iostream>
#include<string>
#include<vector>
#include<math.h>
#include<algorithm>
using namespace std;

//将输入的字符串进行拆分
void make_input(string& input, vector<string>&vec) {
	auto it = input.find(' ');
	vec.push_back(input.substr(0, it));
	vec.push_back(input.substr(it + 1));
}

void calculate(string& input) {
	//空串不处理
	if (input.length() == 0) return;

	vector<string>vec;
	vector<int>ans;
	make_input(input, vec);

	int begin = atoi(vec[0].c_str());
	int end = atoi(vec[1].c_str());

	int temp = 0, sum = 0;
	for (int i = begin; i <= end; i++) {
		temp = i;
		while (temp) {
			sum += pow(temp % 10, 3);
			temp /= 10;
		}
		if (sum == i)
			ans.push_back(i);
		sum = 0;
		temp = 0;
	}
	if (ans.size() == 0) {
		cout << "no" << endl;
		return;
	}
    
	for(int i=0; i<ans.size(); i++){
        if(i==ans.size()-1){
            cout<<ans[i];
        }else{
            cout<<ans[i]<<" ";
        }
    }
    cout<<endl;
}

int main() {
	string input;
	while (getline(cin, input)) {
		calculate(input);
	}
	return 0;
}

 

 

 

题目——删除链表倒数第n个节点(leetcode也有这题)

思路:

题目中要求一趟遍历实现删除倒数第n个节点,可以这样:

用两根指针,一根指针fast先走n+1步。如果此时fast指向空节点,则说明待删除节点是头结点,否则第二根slow指针开始遍历链表。

当fast指针遍历到链表尾时,slow指针此时指向的是待删除节点的前驱节点。

实现代码:

class Solution {
public:
    ListNode *removeNthFromEnd(ListNode *head, int n) {
        if(head==nullptr) return nullptr;
        ListNode * fast=head;
        ListNode *slow=head;
        while(n){
            fast=fast->next;
            n--;
        }
        //说明待删除节点是头结点
        if (fast == nullptr){
            slow = head->next;
            return slow;
        }
        
        while(fast->next){
            slow=slow->next;
            fast=fast->next;
        }
        
        //删除slow指向的后序节点即可
        slow->next=slow->next->next;
        return head;
    }
};

 

 

 

题目三——动态规划题

思路

这种求最优解的,后续结果不影响之前的计算结果的题,就可以用动态规划。粘贴一点我论文里面对于动态规划的讲解:

动态规划算法是求解决策过程最优化的数学方法。解决动态规划问题可以从两方面入手:阶段和决策。

(1)阶段:将原问题的求解过程按照时间或者空间特征来进行分解,依次对每个阶段进行求解,当前阶段的解依赖于之前多阶段的解,但是当前阶段的解无法修改后续阶段的解,即各阶段无后效性。因为一个阶段的解如果存在后效性,则证明此时的阶段划分方法不合理。不断迭代求解各阶段的解,从而获取原问题的最终解。

(2)决策:各阶段在划分之后所采取的动作叫做决策。在实际求解过程中,决策的种类往往在一定范围内。不同的决策往往会影响下一阶段的求解状态。动态规划算法的所有决策应构成最优策略,最优策略的子策略也应该保证其最优性。

对于本题,阶段就是选择了i 个学生,最后一个学生序号为  j 。考察所有的可能情况,情定出 选择学生 j 时数组的极值。

设置一个学生能力值数组stu[j],然后设置二维数组fm[i][j],i表示选取学生的人数,j 表示选取到的最后一人。由于学生的能力值有正有负,因此要用两个数组分别记录选择了 i个学生时,最后一个学生为 j  时,所累积的最大能量值和最小能量值。

那么当状态中其中选择的学生数为 i-1时,依次考察学号为 j-1到 j-d的学生作为学生 j 上一个被选中的学生的情况,记录考察过程中的最大值和最小值,则有状态转移方程:

fm[i][j] = max(fm[i][j], max(fm[i - 1][k] * stu[j], fn[i - 1][k] * stu[j]));
fn[i][j] = min(fn[i][j], min(fm[i - 1][k] * stu[j], fn[i - 1][k] * stu[j]));

再考虑一下边界条件:

  • fm[1][i]由于只有1个人,所以这个人必然是第i个人的能力值,也就是stu[i]

实现代码

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

void calculate(vector<int>&stu, vector<int>&inf){
    vector<vector<long long>>fm(inf[0]+1,vector<long long>(stu.size()+1));
    vector<vector<long long>>fn(inf[0]+1,vector<long long>(stu.size()+1));
    long long ans=0;
    //初始化二维数组
    for(int i=1; i<=stu.size(); i++){
        fm[1][i]=stu[i-1];
        fn[1][i]=stu[i-1];
    }
    
    for (int j = 1 ; j <= stu.size(); j++) {
		for (int i = 2; i <= inf[0]; i++) {
			for (int k = j-1; k >= j - inf[1] && k > 0; k--) {
				//选择i个学生,第i个学生为j时,当前位置最大值fm[i][j]为
				//当前选择学生j以及依次尝试j前的d个学生,选择最大值作为 j 学生前一个学长的学生
				fm[i][j] = max(fm[i][j], max(fm[i - 1][k] * stu[j-1], fn[i - 1][k] * stu[j-1]));
				fn[i][j] = min(fn[i][j], min(fm[i - 1][k] * stu[j-1], fn[i - 1][k] * stu[j-1]));
			}
		}
        //选择不同学生结尾的,共选取了k个学生的各个结果中的最大值作为最终结果进行输出
        ans=max(ans,fm[inf[0]][j]);
	}
    cout<<ans<<endl;
}

int main(){
    int n=0;
    int temp=0;
    vector<int>stu;
    vector<int>inf;
    while(cin>>n){
        while(n--){
            cin>>temp;
            stu.push_back(temp);
        }
        //记录学生数和编号差
        cin>>temp>>n;
        inf.push_back(temp);
        inf.push_back(n);
        calculate(stu,inf);
        stu.clear();
        inf.clear();
    }
    
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值