算法与设计分析--分治算法的设计与分析

news2024/11/19 13:23:25

某不知名学校的第二次算法实验报告,一共四道题 全部来自力扣

第一题 
​​​​​​169. 多数元素

题目描述:

给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

示例 1:

输入: [3,2,3]

输出: 3

示例 2:

输入: [2,2,1,1,1,2,2]

输出: 2

这道题的话我的思路一开始是想到哈希,记录每个数据出现次数 最多的那个就是答案,但是发现数据到了1e5 ,而且下面的题目思考提醒可以用时间复杂度O(n) 空间复杂度O(1)的算法,那么额外开辟空间去整哈希表肯定是不行的了,只能原地操作

排序的算法时间复杂度是O(logn) 接近O(n)的水平, 而且也是原地操作,最重要是思路简单

把所有数排序,中间那个数字不是就一定出现次数大于n/2了吗

代码如下:

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        int k =  nums.size();
        return nums[ k / 2 ];
    }
};

很简单是吧,排序函数就不自己写了,这道题考的也不是排序

第二题

53. 最大子数组和

题目描述:

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4]

输出: 6

解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

首先这道题很容易想到滑动窗口,但是突然发现,这个题他的窗口大小是会变化的,而且并不是一个队列结构,那我们只能另辟蹊径,我们发现,最大子序列他的第一个和最后一个元素一定是正数

我们依次往后累加,同时保留最大序列,如果发现整个序列为负时,则需要更新整个序列

sum = num

完整代码+注释如下:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
    int res = nums[0]; // 保存答案序列
    int sum = 0;
    for(int num : nums)
    {
        if(sum > 0 )
        sum += num; //依次累加
        else
        sum = num; // 序列为负数 更新起点

        res = max(res, sum); // 每次取最大序列
    }
    return res;
    }
};

第三题

215. 数组中的第K个最大元素

题目描述:

在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

示例 1:

输入: [3,2,1,5,6,4] 和 k = 2

输出: 5

示例 2:

输入: [3,2,3,1,2,4,5,5,6] 和 k = 4

输出: 4

说明:

你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度

思路:这道题就是快排的思路,本质上还是个快排,而且题目建议最好是用接近O(n)的时间复杂度,那很明显就是用快排思路做,但是很多语言都有排序函数,比如c++的库函数sort,会在元素少的时候有归并排序,元素多的时候用快速排序,时间复杂度接近O(n)

先放一个库函数的代码:

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        int l = nums.size();
        sort(nums.begin(), nums.end());
        return nums[l - k];
    }
};

很简单对吧 但是这道题毕竟要考的是快排,把题目的本质用库函数实现了,实在不推荐

正常写法(求第K个数):

#include <iostream>

using namespace std;

const int N = 100010;

int q[N];

int quick_sort(int q[], int l, int r, int k)
{
    if (l >= r) return q[l];

    int i = l - 1, j = r + 1, x = q[l + r >> 1];
    while (i < j)
    {
        do i ++ ; while (q[i] < x);
        do j -- ; while (q[j] > x);
        if (i < j) swap(q[i], q[j]);
    }

    if (j - l + 1 >= k) return quick_sort(q, l, j, k);
    else return quick_sort(q, j + 1, r, k - (j - l + 1));
}

int main()
{
    int n, k;
    scanf("%d%d", &n, &k);

    for (int i = 0; i < n; i ++ ) scanf("%d", &q[i]);

    cout << quick_sort(q, 0, n - 1, k) << endl;

    return 0;
}

第四题

932. 漂亮数组

题目描述:

如果长度为 n 的数组 nums 满足下述条件,则认为该数组是一个 漂亮数组 :

  • nums 是由范围 [1, n] 的整数组成的一个排列。
  • 对于每个 0 <= i < j < n ,均不存在下标 ki < k < j)使得 2 * nums[k] == nums[i] + nums[j] 。

给你整数 n ,返回长度为 n 的任一 漂亮数组 。本题保证对于给定的 n 至少存在一个有效答案。

示例 1 :

输入:n = 4
输出:[2,1,4,3]

示例 2 :

输入:n = 5
输出:[3,1,2,5,4]

提示:

  • 1 <= n <= 1000

先分析信息:

1.这是一段连续的序列

2.下标的大小i < k < j

3.条件是要不成立 而左边是2*nums[k] 左边是偶数 且只需要其中一个有效答案

先顺着分治的思想观察一下(废话,这次实验不就是分治吗) 把数组从中间切开 左边和右边满足什么规律?

好的,看样例好像确实看不出什么,大概率是道搞数学的

发现他答案不止一组,n=4时候  [1,3,2,4]可行

n = 5 [1,5,3,2,4]可行

加上题目给的*2条件 我们可以推出 偶数 != 奇数 + 偶数  两边不会相等

我们设 x = nums[i] y = nums[k] z = nums[j]

对于一个正整数 N ,我们寻找中点将其等分成两部分 ,left 和 right ,如果 left 和 right 都是漂亮数组,同时 left 部分全部是奇数 , right 部分全部是偶数 ,那么left + right 组成的数组一定也是漂亮数组 。

同时可以发现 

如果x, y, z 是漂亮数组,则 k * x + b, k * y + b, k * z + b 一定也是漂亮数组;

那么就可以往下分了左端 (n + 1) /2 分奇数 右端 n / 2 分偶数

代码+注释如下:

class Solution {
public:
    vector<int> beautifulArray(int n) {
        vector<int> ans, left, right;
        
            left = beautifulArray((n+1)/2);
            right = beautifulArray(n/2);

            for(int l : left){
                ans.push_back(l * 2 - 1); //回溯
            }

            for(int r : right){
                ans.push_back(r * 2); //回溯
            }
        
//这里代码先push左端后右端 所以ans左边全是奇数 右边全是偶数 但是符合题目要求
        else ans.push_back(1);
        return ans;

    }
};

当然 看完别人题解后 发现动态规划也能写,原理一样 ,只是思维量更大一点

代码如下:

class Solution {
public:
    unordered_map<int, vector<int>> mp;
    vector<int> beautifulArray(int n) {
        vector<vector<int>> dp(n+1);
        
        // 初始化
        dp[1].push_back(1);

        // 状态转移
        for(int i=2; i<=n; ++i){
            for(int l : dp[(i+1)/2]){
                dp[i].push_back(l * 2 - 1);
            }
            for(int r : dp[i/2]){
                dp[i].push_back(r * 2);
            }
        }
        return dp[n];
    }
};

前面几题都是来划水的,最后一题确实是巧妙 主要是分治思想没有体会精髓,平时哪怕用了也不会想到,平时就算要解题也不会第一时间想到分治

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1011354.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker概念通讲

目录 什么是Docker&#xff1f; Docker的应用场景有哪些&#xff1f; Docker的优点有哪些&#xff1f; Docker与虚拟机的区别是什么&#xff1f; Docker的三大核心是什么&#xff1f; 如何快速安装Docker&#xff1f; 如何修改Docker的存储位置&#xff1f; Docker镜像常…

敏捷管理的4价值观12准则

一、敏捷管理的的4个价值观 个体和交互胜过流程和工具可工作的软件胜过面面俱到的文档客户合作胜过合同谈判响应变化胜过遵循计划 二、敏捷管理的12条准则 上篇解读了对于敏捷价值观的理解&#xff0c;这篇来聊一聊敏捷的12指导准则。关于敏捷宣言的12条准则的原始描述&…

Dokcer搭建Apache Guacamole堡垒机

一、什么是堡垒机 “堡垒机” 这个词通常指的是 “堡垒机器”&#xff08;Bastion Host&#xff09;的简称。堡垒机是一种计算机系统或网络设备&#xff0c;用于增强计算机网络的安全性。它在网络中充当一个重要的安全关口&#xff0c;通过限制对内部网络的访问&#xff0c;帮…

LeetCode(力扣)860. 柠檬水找零Python

LeetCode860. 柠檬水找零 题目链接代码 题目链接 https://leetcode.cn/problems/lemonade-change/ 代码 class Solution:def lemonadeChange(self, bills: List[int]) -> bool:five 0ten 0twenty 0for i in range(len(bills)):if bills[i] 5:five 1if bills[i] 10…

pdf怎么压缩的小一点?pdf文件压缩方法汇总

在日常生活中&#xff0c;我们常常需要处理大量的PDF文件。有时候&#xff0c;这些PDF文件可能因为内容丰富、结构复杂而体积庞大&#xff0c;给我们的存储和传输带来了不便。那么&#xff0c;如何将这些PDF文件压缩得小一点&#xff0c;以便更方便地使用呢&#xff1f; 一、嗨…

Git(6)——GitHub

目录 一、简介 二、概要 三、注册 ​四、创建仓库 五、推送本地代码 六、拉取远端代码 一、简介 在Git&#xff08;5&#xff09;中&#xff0c;我们已经对Git分支的概念和用法有了一定了解&#xff0c;对于在本地进行代码版本管理&#xff0c;其实当前所学的东西基本已经…

【个人博客系统 × Redis】“最后的升级” · 连接Redis · Redis的基本使用

【JavaEE】进阶 个人博客系统&#xff08;7&#xff09; 文章目录 【JavaEE】进阶 个人博客系统&#xff08;7&#xff09;1. linux安装Redis1.1 通过yum商店下载Redis1.2 启动Redis1.3 操作Redis 2. Redis的基本使用&#xff08;关键字大小写不区分&#xff09;2.1 set2.2 g…

Lombok中的@Builder注解的使用

Lombok中的Builder注解的使用 作用 Builder注解的作用主要是用来生成对象&#xff0c;并且可以为对象链式赋值。 引入依赖 因为Builder注解是lombok中的东西&#xff0c;所以第一步我们需要引入lombok的依赖&#xff0c;如下图&#xff1a; 第二步给实体类加上Builder注解…

每日一博 - Token Based Authentication VS HMAC Authentication 实现web安全

文章目录 概念HMAC工作原理 概念 Token Based Authentication和HMAC&#xff08;Hash-based Message Authentication Code&#xff09;Authentication都是用于身份验证和数据完整性验证的安全机制&#xff0c;但它们有不同的工作方式和适用场景。以下是它们的主要区别和比较&a…

idea把项目打成jar包步骤详解

最近产品需要预研一个小功能&#xff0c;开始后在本地开发测试好之后&#xff0c;需要打成jar提供出去&#xff0c;今天弄完了&#xff0c;决定把这个步骤记录下来&#xff0c;便于以后轻车熟路。 打成jar要有mian方法的入口&#xff0c;所以我们在代码中需要定义一个main方法&…

学Python的漫画漫步进阶 -- 第七步

学Python的漫画漫步进阶 -- 第七步 七、字符串7.1 字符串的表示方式7.1.1 普通字符串7.1.2 原始字符串7.1.3 长字符串 7.2 字符串与数字的相互转换7.2.1 将字符串转换为数字7.2.2 将数字转换为字符串 7.3 格式化字符串7.3.1 使用占位符7.3.2 格式化控制符 7.4 操作字符串7.4.1 …

四、数学建模之图与网络模型

1.定义 2.例题及软件代码求解 一、定义 1.图和网络是相关概念 &#xff08;1&#xff09;图&#xff08;Graph&#xff09;&#xff1a;图是数学和计算机科学中的一个抽象概念&#xff0c;它由一组节点&#xff08;顶点&#xff09;和连接这些节点的边组成。图可以是有向的&…

VSCode配置c/c++环境 MinGW-W64 下载、安装与配置(支持最新版的GCC,目前 GCC 13.2.0) 彻底删除vscode(包括插件及配置!)

目录 一、简介 二、下载 1 旧版安装&#xff08;8.1.0&#xff09; 从 sourceforge.net 下载 2 新版安装(本次采用较新版本~~~) 从 github 下载 从 镜像站点 下载 自己编译 三、安装与配置 1. 在线安装&#xff08;这里仅作参考了解&#xff09; 2. 离线安装&…

JavaScript 知识扫盲

JavaScript 知识扫盲 写在前面一、JavaScript 写入形式二、常用输入输出三、JS 是动态类型语言四、运算符五、数组1、数组创建2、获取和修改数组元素3、新增元素4、删除元素 六、函数七、对象1、对象的创建2、属性方法的使用 八、JavaScript 和 Java 对比九、事件1、常见事件2、…

【MySQL系列】MySQL数据库索引详解

目录 一、为什么要用索引&#xff1f; 二、什么是索引&#xff1f; 三、MySQL索引使用场景 四、索引的原理 五、MySQL的存储引擎 六、索引的数据结构 七、索引如何使用 八、实际使用示例 九、优缺点、使用建议和注意事项 十、为什么Mysql不选择Hash索引&#xff1f; …

k8s集群中流水线部署微服务

k8s集群中流水线发布微服务 一、流水线部署微服务部署流程 二、微服务发布流程 pipeline {agent {node {label maven}}parameters {string(name: PROJECT_VERSION, defaultValue: v1.0, description: )string(name: PROJECT_NAME, defaultValue: , description: )}environment…

json转换

json转html {"DS": [{"PROVINCE": "陕西省","ADMIN_CODE_CHN": "610600","STATION_ID_C": "53845","LON": "109.4497","V31001_S": 10,"V31001_X": 0},{&quo…

【前端知识】+new Date()是什么?

一、new Date()的使用 new Date()是JavaScript中用于获取当前日期和时间的内置函数。它返回一个表示当前日期和时间的Date对象。如下所示&#xff1a; 通过Date.prototype可以查看Date对象的所有方法&#xff1a; constructor: ƒ Date() getDate: ƒ getDate() getDay: ƒ …

学习笔记|IO中断|中断号大于31|中断优先级|简易中央门禁|STC32G单片机视频开发教程(冲哥)|第十六集:IO中断

文章目录 1.什么是IO中断?2.IO中断的用法13.1.3 端口中断模式配置寄存器(PxIM0&#xff0c;PxIM1)13.1.1 端口中断使能寄存器&#xff08;PxINTE)13.1.2端口中断标志寄存器(PxINTF)13.2 范例程序3.1.编写P35口的IO中断实现&#xff1a; 3.中断优先级的设置3.1 为什么会出现数码…

C++ 算法学习 之 vector assign

参考c官方手册 vector::assign是C标准模板库中的一个函数&#xff0c;它的主要功能是给vector容器重新赋值。具体来说&#xff0c;vector::assign函数会删除vector中的所有元素&#xff0c;并根据用户提供的参数重新填充。 这个函数有三种形式&#xff1a; template <cla…