当前位置: 首页 > news >正文

剑指offer经典题目整理(七)

一、经典dp——最大子数组之和

1.链接

53. 最大子数组和 - 力扣(LeetCode)

2.描述

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

3.思路

这是经典的动归问题,一般解决动归问题分四步:

1.描述状态:f(i) : 以第i个为子数组结尾的最大子数组之和

2.状态方程:f(i) = max(f(i-1) + arr[ i ],arr[ i ])

解析:我们假设第i个结尾的最大子数组之和为f(i),而我们若想知道下一个f(i+1),我们需要判断,arr[ i ] 在加上以前一个为底的最优解,也就是加上后较大还是不加较大,通过这个方式走dp就可以得到每一个为子数组底时的最优解,再其中选出一个最大的就是本题答案

3.初始状态:f(0)= arr[ 0 ]

4.dp容器:一维数组

关于本题的优化:本题中,我们实际并不需要记录每一步的最优解,只需要找到其中最大的,所以实际不需要容器去记录,只需要有一个整形去记录下最优解即可

4.参考代码

class Solution {
public:int maxSubArray(vector<int>& nums) {int* dp = new int[nums.size()];dp[0] = nums[0];int ret = nums[0];for(int i = 1;i<nums.size();i++){dp[i] = max(nums[i]+dp[i-1],nums[i]);if(ret < dp[i]){ret = dp[i];}}return ret;}
};

优化后:

class Solution {
public:int maxSubArray(vector<int>& nums) {int dp = nums[0];int ret = nums[0];for(int i = 1;i<nums.size();i++){dp = max(nums[i]+dp,nums[i]);if(ret < dp){ret = dp;}}return ret;}
};

二、字符串回文

1.链接

回文数索引_牛客题霸_牛客网 (nowcoder.com)

2.描述

3.思路

关于字符串回文的题目,我们要想到头尾指针的思路,回文字符串的特点就是头指针和尾指针往中间一起走,都相同,这题说一定有一个解满足条件,说明我们只需要头尾指针去扫描,当遇到不同时,删除任意一个后再判断是否回文,若不是则说明另一个下标就是要删除的

4.参考代码

#include <iostream>
using namespace std;bool is_pal(const string& str)//判断字符串回文
{int begin = 0;int end = str.size()-1;while(begin < end){if(str[begin++] != str[end--]){return false;}}return true;;
}int main() 
{int n;cin >> n;string str;while(n--){cin >> str;if(is_pal(str))//若已经是回文,则不需要判断{cout << -1 << endl;}int begin = 0;int end = str.size()-1;while(begin < end){if(str[begin] != str[end]){str.erase(begin,1);if(is_pal(str)){cout << begin << endl;}else {cout << end << endl;}break;}begin++;end--;}}return 0;
}

三、把数组排列成最小数

1.链接

把数组排成最小的数_牛客题霸_牛客网 (nowcoder.com)

2.描述

输入一个非负整数数组numbers,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。

例如输入数组[3,32,321],则打印出这三个数字能排成的最小数字为321323。

1.输出结果可能非常大,所以你需要返回一个字符串而不是整数
2.拼接起来的数字可能会有前导 0,最后结果不需要去掉前导 0

3.思路

这里利用sort函数去实现排序,这道题其实是贪心算法,也就是局部最优解的方式,每个相邻的两个数拼接起来都是当前最小的顺序,则可以保证整个序列拼接起来就是最小的,我们可以写一个回调函数去交给sort去排

4.参考代码

#include <string>
class Solution 
{
public:static bool cmp(int x,int y){string xs = to_string(x);string ys = to_string(y);string A = xs;A+=ys;string B =ys;B+=xs;return A<B;}string PrintMinNumber(vector<int>& numbers) {if(numbers.empty()){return "";}sort(numbers.begin(),numbers.end(),cmp);string ret;for(int i =0;i<numbers.size();i++){ret += to_string(numbers[i]);}return ret;}
};

四、单链表找公共节点

1.链接

两个链表的第一个公共结点_牛客题霸_牛客网 (nowcoder.com)

2.描述

输入两个无环的单向链表,找出它们的第一个公共结点,如果没有公共节点则返回空。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)

3.思路

快慢指针,先统计两个链表的长度,然后让长链表先走他们的差距步长,然后再一起走,判断相等

4.参考代码

class Solution 
{
public:int List_len(ListNode* pHead){int count = 0;ListNode* cur = pHead;while(cur){count++;cur = cur->next;}return count;}ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {int len1 = List_len(pHead1);int len2 = List_len(pHead2);int gap;ListNode* fast;ListNode* slow;if(len1 >= len2){gap = len1 - len2;fast = pHead1;slow = pHead2;}else{			gap = len2 -len1;fast = pHead2;slow = pHead1;}while(gap--)//先让长的先走gap步{fast = fast->next;}while(fast && slow)//没有交点,通过这里退出{if(fast == slow)//找到交点,通过这里退出{break;}fast = fast->next;slow = slow->next;}//此时若是有交点,则通过break退出,fast和slow同时指向公共节点//若是没有交点,fast和slow也指向空,直接返回也可以return fast;}
};

五、二叉树判断深度

1.链接

二叉树的深度_牛客题霸_牛客网 (nowcoder.com)

2.描述

给一颗二叉树,要求返回二叉树的高度

3.思路

(1)递归思想

递归的往下遍历,分别得到左右子树的高度,然后比较返回大的那个,也可以是回溯算法的思想去解决

(2)层序遍历的思想

二叉树的层序遍历是利用队列的特性,将队首的节点出队列时,将其左右子树的节点放到队尾排队,从第一层开始,每次可以通过队列内的size大小得到每一层有多少个节点,因此可以分层次的将每一层的数据打印出来,因此也能够用这个办法去统计有多少层

4.参考代码

(1)递归思想

class Solution 
{
public:int TreeDepth(TreeNode* pRoot) {if(pRoot == nullptr){return 0;}int Left = TreeDepth(pRoot->left) + 1;int Right = TreeDepth(pRoot->right) + 1;return Left > Right ? Left : Right;}
};

(2)层序遍历的思想

class Solution 
{
public:int TreeDepth(TreeNode* pRoot) {if(pRoot == nullptr)//为空则返回0{return 0;}int len = 0;//用来统计高度/层数queue<TreeNode*> q;q.push(pRoot);while(!q.empty()){int size = q.size();//记录每一层的大小,每次出完一层会更新size值for(int i = 0;i<size;i++)//将每一层的数据都遍历pop,并且把下一层的数据放到队列中{TreeNode* tmp = q.front();q.pop();if(tmp->left != nullptr){q.push(tmp->left);}if(tmp->right != nullptr){q.push(tmp->right);}}len++;//每出完一层就统计一层}return len;}
};

总结

这次的总结里,有几题特别经典的题目,例如动归,找节点等等

相关文章:

  • Vue3 大量赋值导致reactive响应丢失问题
  • 显卡基础知识及元器件原理分析
  • Linux hdparm命令教程:优化硬盘性能和读写速度(附实例详解和注意事项)
  • Design Script官方案例解析2:程序简写
  • 从后端获取文件数据并导出
  • 应急响应靶机训练-Web3题解
  • 【Frida】10_用鼠标自动标记棋盘上的雷区(一键过关)
  • C/C++炸弹人游戏
  • spring cloud gateway k8s优雅启停
  • (C语言)球球大作战
  • 十、C#基数排序算法
  • 实时数仓之实时数仓架构(Doris)
  • Svg Flow Editor 原生svg流程图编辑器(三)
  • Java安全 反序列化(4) CC1链-LazyMap版
  • LLM - 大语言模型的分布式训练 概述
  • [译]前端离线指南(上)
  • Android单元测试 - 几个重要问题
  • AWS实战 - 利用IAM对S3做访问控制
  • css系列之关于字体的事
  • es6--symbol
  • Github访问慢解决办法
  • Java|序列化异常StreamCorruptedException的解决方法
  • Laravel5.4 Queues队列学习
  • Redis字符串类型内部编码剖析
  • 诡异!React stopPropagation失灵
  • 提醒我喝水chrome插件开发指南
  • 微信小程序填坑清单
  • 关于Kubernetes Dashboard漏洞CVE-2018-18264的修复公告
  • 进程与线程(三)——进程/线程间通信
  • # 执行时间 统计mysql_一文说尽 MySQL 优化原理
  • #AngularJS#$sce.trustAsResourceUrl
  • #Java第九次作业--输入输出流和文件操作
  • #Js篇:单线程模式同步任务异步任务任务队列事件循环setTimeout() setInterval()
  • #ubuntu# #git# repository git config --global --add safe.directory
  • #设计模式#4.6 Flyweight(享元) 对象结构型模式
  • (Bean工厂的后处理器入门)学习Spring的第七天
  • (C语言)strcpy与strcpy详解,与模拟实现
  • (附源码)spring boot公选课在线选课系统 毕业设计 142011
  • (转)shell调试方法
  • (转载)从 Java 代码到 Java 堆
  • .Net core 6.0 升8.0
  • .NET Core 将实体类转换为 SQL(ORM 映射)
  • .NET 中 GetProcess 相关方法的性能
  • .NET版Word处理控件Aspose.words功能演示:在ASP.NET MVC中创建MS Word编辑器
  • .NET轻量级ORM组件Dapper葵花宝典
  • .NET应用架构设计:原则、模式与实践 目录预览
  • .skip() 和 .only() 的使用
  • [ 云计算 | AWS ] AI 编程助手新势力 Amazon CodeWhisperer:优势功能及实用技巧
  • []利用定点式具实现:文件读取,完成不同进制之间的
  • [2010-8-30]
  • [20180129]bash显示path环境变量.txt
  • [Android 数据通信] android cmwap接入点
  • [Docker]六.Docker自动部署nodejs以及golang项目
  • [JS设计模式]Prototype Pattern
  • [Kubernetes]9. K8s ingress讲解借助ingress配置http,https访问k8s集群应用