MS100 [041-060]

本文集解答了多种经典算法问题,包括括号排列数、最长递减子序列、部分有序数组查找等,提供了详尽的思路解析及代码示例。

MS100 [046]

括号排列数

四对括号可以有多少种匹配排列方式?比如两对括号可以有两种:()()和(())

思路:12种

MS100 [047]

最长递减子序列

求一个数组的最长递减子序列比如{9,4,3,2,5,4,3,2}的最长递减子序列为{9,5,4,3,2}

思路:经典动态规划,方案一,记录max[i]为以a[i]接尾的最长递减子序列长度,从0到n-1不断更新max数组即可。O(n^2)

方案二,使用数组b[t]表示长度为t的递减子序列的末尾值的最大值,显然b[t]数组单调递减(初始化为最小值)。每次二分查找b数组,找t使b[t-1] > a[i] && b[t] <= a[i],更新b[t] = a[i]。最大的有效t值即为所求。恢复结果时,先找到b[t],然后从后往前扫描数组a。O(n*logn)

MS100 [048]

部分有序数组查找

微软:
一个数组是由一个递减数列左移若干位形成的,比如{4,3,2,1,6,5}
是由{6,5,4,3,2,1}左移两位形成的,在这种数组中查找某一个数。

思路:数组的一半是有序的,那么可以通过判断key是否在有序的一半中来决定递归的子问题。

如果a[mid] <= a[0] :那么a[0...mid]是纯递减数组;可以简单比较出key是否在a[0..mid]中,如果在那么问题就是标准的二分查找了;否则,a[mid+1...n-1]就是原问题的子问题了。

MS100 [053]

字符串的排列
题目:输入一个字符串,打印出该字符串中字符的所有排列。

思路:递归实现。

MS100 [054]

调整数组顺序使奇数位于偶数前面

思路:类似与快速排序的partition过程,设置一个头指针从前往后指向第一个偶数,一个尾指针从后往前指向第一个奇数,交换他们,然后继续循环直到相遇即可。

MS100 [055]

异常时安全的赋值重载函数

类CMyString的声明如下:
class CMyString
{
public:
      CMyString(char* pData = NULL);
      CMyString(const CMyString& str);
      ~CMyString(void);
      CMyString& operator = (const CMyString& str);
private:
      char* m_pData;
};
请实现其赋值运算符的重载函数,要求异常安全,即当对一个对象进行赋值时发生异常,对象的状态不能改变。
分析:首先我们来看一般C++教科书上给出的赋值运算符的重载函数:
CMyString& CMyString::operator =(const CMyString &str)
{
      if(this == &str)
            return *this;
      delete []m_pData;
      m_pData = NULL;
      m_pData = new char[strlen(str.m_pData) + 1];
      strcpy(m_pData, str.m_pData);
      return *this;
}
我们知道,在分配内存时有可能发生异常。当执行语句new char[strlen(str.m_pData) + 1]发生异常时,程序将从该赋值运算符的重载函数退出不再执行。注意到这个时候语句delete []m_pData已经执行了。也就是说赋值操作没有完成,但原来对象的状态已经改变。也就是说不满足题目的异常安全的要求。
为了满足异常安全这个要求,一个简单的办法是掉换new、delete的顺序。先把内存new出来用一个临时指针保存起来,只有这个语句正常执行完成之后再执行delete。这样就能够保证异常安全了。
下面给出的是一个更加优雅的实现方案:
CMyString& CMyString::operator =(const CMyString &str)
{
      if(this != &str)
      {
            CMyString strTemp(str);
            char* pTemp = strTemp.m_pData;
            strTemp.m_pData = m_pData; //这样在strTemp析构的时候会析构掉m_pData
            m_pData = pTemp;
      }
      return *this;
}
该方案通过调用构造拷贝函数创建一个临时对象来分配内存。此时即使发生异常,对原来对象的状态没有影响。交换临时对象和需要赋值的对象的字符串指针之后,由于临时对象的生命周期结束,自动调用其析构函数释放需赋值对象的原来的字符串空间。整个函数不需要显式用到new、delete,内存的分配和释放都自动完成,因此代码显得比较优雅。

MS100 [056]

最长公共字串(LCS,Longest Common Subsequence)

如果字符串一的所有字符按其在字符串中的顺序出现在另外一个字符串二中,则字符串一称之为字符串二的子串。
注意,并不要求子串(字符串一)的字符必须连续出现在字符串二中。
请编写一个函数,输入两个字符串,求它们的最长公共子串,并打印出最长公共子串。

思路:对字符串X和Y,从后往前递推,

若xm==yn,则LCS等于(Xm-1,Yn-1)的LCS加上xm(=yn)。

若xm!=yn,则LCS等于(Xm-1,Yn)和(Xm,Yn-1)中LCS最大的那个。

递归太慢,用动态规划,从第一行开始逐行构造LCS值,并用一个二维数组存储每个xm,yn点所做的选择。

MS100 [057]

从尾到头输出链表
题目:输入一个链表的头结点,从尾到头反过来输出每个结点的值。链表结点定义如下:
struct ListNode
{
      int       m_nKey;
      ListNode* m_pNext;
};
分析:用栈或者递归。注意边界。
 void PrintListReversely(ListNode* pListHead)
{
      if(pListHead != NULL)
      {
            // Print the next node first
            if (pListHead->m_pNext != NULL)
            {
                  PrintListReversely(pListHead->m_pNext);
            }
            // Print this node
            printf("%d", pListHead->m_nKey);
      }
}
扩展:该题还有两个常见的变体:
1.       从尾到头输出一个字符串;
2.       定义一个函数求字符串的长度,要求该函数体内不能声明任何变量。return fun(&a[i+1])+1;

MS100 [058]

不能被继承的类
题目:用C++设计一个不能被继承的类。

首先想到的是在C++ 中,子类的构造函数会自动调用父类的构造函数。同样,子类的析构函数也会自动调用父类的析构函数。要想一个类不能被继承,我们只要把它的构造函数和析构函数都定义为私有函数。那么当一个类试图从它那继承的时候,必然会由于试图调用构造函数、析构函数而导致编译错误。
 可是这个类的构造函数和析构函数都是私有函数了,我们怎样才能得到该类的实例呢?
这难不倒我们,我们可以通过定义静态来创建和释放类的实例。
 
基于这个思路,我们可以写出如下的代码:
// Define a class which can't be derived from
class FinalClass1
{
public:
      static FinalClass1* GetInstance() 
      {
            return new FinalClass1;
      }
      static void DeleteInstance( FinalClass1* pInstance)
      {
            delete pInstance;
            pInstance = 0;
      }
private:
      FinalClass1() {}
      ~FinalClass1() {}
};
 
这个类是不能被继承,但在总觉得它和一般的类有些不一样,使用起来也有点不方便。比如,我们只能得到位于堆上的实例,而得不到位于栈上实例。
 能不能实现一个和一般类除了不能被继承之外其他用法都一样的类呢?办法总是有的,不过需要一些技巧。请看如下代码:
// Define a class which can't be derived from
template <typename T> class MakeFinal
{
      friend T;
private:
      MakeFinal() {}
      ~MakeFinal() {}
};
class FinalClass2 : virtual public MakeFinal<FinalClass2>
{
public:
      FinalClass2() {}
      ~FinalClass2() {}
};
这个类使用起来和一般的类没有区别,可以在栈上、也可以在堆上创建实例。尽管类MakeFinal<FinalClass2>的构造函数和析构函数都是私有的,但由于类FinalClass2是它的友元函数,因此在FinalClass2中调用MakeFinal<FinalClass2>的构造函数和析构函数都不会造成编译错误。
 但当我们试图从FinalClass2继承一个类并创建它的实例时,却不同通过编译。
class Try : public FinalClass2
{
public:
      Try() {}
      ~Try() {}
};
Try temp; 
由于类FinalClass2是从类MakeFinal<FinalClass2>虚继承过来的,在调用Try的构造函数的时候,会直接跳过FinalClass2而直接调用MakeFinal<FinalClass2>的构造函数。非常遗憾的是,Try不是MakeFinal<FinalClass2>的友元,因此不能调用其私有的构造函数。
基于上面的分析,试图从FinalClass2继承的类,一旦实例化,都会导致编译错误,因此是FinalClass2不能被继承。这就满足了我们设计要求。

MS100 [060]

在O(1)时间内删除链表结点。
题目:给定链表的头指针和一个结点指针,在O(1)时间删除该结点。

思路:删除的实质是删除它的内容。所以!可以复制下一个节点的内容到本节点,然后删除下一个节点。注意当删除尾部节点时,仍需要从头指针遍历,复杂度O(n)。但整个算法的平均复杂度是O(1)。

先展示下效果 https://pan.quark.cn/s/e81b877737c1 Node.js 是一种基于 Chrome V8 引擎的 JavaScript 执行环境,它使开发者能够在服务器端执行 JavaScript 编程,显著促进了全栈开发的应用普及。 在 Node.js 的开发流程中,`node_modules` 文件夹用于存储所有依赖的模块,随着项目的进展,该文件夹可能会变得异常庞大,其中包含了众多可能已不再需要的文件和文件夹,这不仅会消耗大量的硬盘空间,还可能减慢项目的加载时间。 `ModClean 2.0` 正是为了应对这一挑战而设计的工具。 `ModClean` 是一款用于清理 `node_modules` 的软件,其核心功能是移除那些不再被使用的文件和文件夹,从而确保项目的整洁性和运行效率。 `ModClean 2.0` 是此工具的改进版本,在原有功能上增加了更多特性,从而提高了清理工作的效率和精确度。 在 `ModClean 2.0` 中,用户可以设置清理规则,例如排除特定的模块或文件类型,以防止误删重要文件。 该工具通常会保留项目所依赖的核心模块,但会移除测试、文档、示例代码等非运行时必需的部分。 通过这种方式,`ModClean` 能够协助开发者优化项目结构,减少不必要的依赖,加快项目的构建速度。 使用 `ModClean` 的步骤大致如下:1. 需要先安装 `ModClean`,在项目的根目录中执行以下命令: ``` npm install modclean -g ```2. 创建配置文件 `.modcleanrc.json` 或 `.modcleanrc.js`,设定希望清理的规则。 比如,可能需要忽略 `LICENSE` 文件或整个 `docs`...
2026最新微信在线AI客服系统源码 微信客服AI系统是一款基于PHP开发的智能客服解决方案,完美集成企业微信客服,为企业提供7×24小时智能客服服务。系统支持文本对话、图片分析、视频分析等多种交互方式,并具备完善的对话管理、人工转接、咨询提醒等高级功能。 核心功能 ### 1.  智能AI客服 #### 自动回复 - **上下文理解**:系统自动保存用户对话历史,AI能够理解上下文,提供连贯的对话体验 - **个性化配置**:可自定义系统提示词、最大输出长度等AI参数 #### 产品知识库集成 - **公司信息**:支持配置公司简介、官网、竞争对手等信息 - **产品列表**:可添加多个产品,包括产品名称、配置、价格、适用人群、特点等 - **常见问题FAQ**:预设常见问题及答案,AI优先使用知识库内容回答 - **促销活动**:支持配置当前优惠活动,AI会自动向用户推荐 ### 2. 多媒体支持 #### 图片分析 - 支持用户发送图片,AI自动分析图片内容 - 可结合文字描述,提供更精准的分析结果 - 支持常见图片格式:JPG、PNG、GIF、WebP等 #### 视频分析 - 支持用户发送视频,AI自动分析视频内容 - 视频文件自动保存到服务器,提供公网访问 - 支持常见视频格式:MP4、等 ### 3.  人工客服转接 #### 关键词触发 - **自定义关键词**:可配置多个转人工触发关键词(如:人工、客服、转人工等) - **自动转接**:用户消息包含关键词时,自动转接给指定人工客服 - **友好提示**:转接前向用户发送提示消息,提升用户体验 #### 一键介入功能 - **后台管理**:管理员可在对话管理页面查看所有对话记录 - **快速转接**:点击"一键介入"按钮,立即将用户转接给人工客服
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值