【总结】常见编程题型总结1-数据结构&算法

更新中…

  本文主要概括总结了一些面试中编程题目的分类,以及常见的一些解决办法。
题目分类主要为两种方式:(1)按照 数据结构 分类;(2)按照 算法思想 进行分类。

按照数据结构划分

  首先了解各个数据结构的一些基本特性,然后才能找到适合的场景。而在面试中,主要考察的是你对于不同数据结构的性质的理解。

基本类型

不使用中间变量,交换两个数值变量的值

  • 乘除法
  • 异或运算

数组 - 1维

数组的特性

随机访问

(1)【随机性】 数组具有随机访问的特性(根据下标,快速定位到数据)。所以可以利用一定的hash法,将数据与其下标形成一定的映射。(比如:年龄为1 到 35,那么可以映射到一个 整型数组A中, A[i]中 i 表示 年龄,此时我们只是应用了下标,而实际存储数据的空间并没有使用,所以我们可以利用其做其他事情,比如说统计人数)

(2)【hash应用信号】当数组中含有有限范围的整型时,那么这类问题很可能可以通过利用数据与下标的hash关系得以解决。

相关题目
* 【下标与hash217. Contains Duplicate

1维数组 + 查找 + 有序

数组中求第K大数
问题:

第 k 大的数一定能 找到?(二分查找的过程不会跳过?)
每次排除了无效信息,不断排除,一定可以找到 k 。(排除思维理解二分查找,思想和这里很像

1维数组 与 回溯

【数组 + 排列 + 回溯(枚举)】46. Permutations
【数组 + 排列 + 回溯 + 去重47. Permutations II

环形数组

这类问题下标的控制要尤其注意。
(示例2:【栈 + 环形数组503. Next Greater Element II

数组 - 2维

  二维数组通常可以用来刻画地图规划,棋类等问题。在解决这些问题时,都用到了重要的算法思想(后面会介绍)。

地图类问题

  地图规划类问题,通常可以通过动态规划回溯法来解决。(见下面例子)

【数组 + 回溯法 + 字符地图 + 存在类问题79. Word Search

【数组 + 动态规划 + 无障碍方格地图 + 最值类问题64. Minimum Path Sum

【数组 + 动态规划 + 路径数量计算问题】62. Unique Paths (之所以说其动态规划,因需考虑多阶段决策)

【数组 + 动态规划 + 有障碍地图 + 路径数量计算】63. Unique Paths II ( 在上面题目上加入有障碍)

感想
  【解决复杂问题62. Unique Paths63. Unique Paths II 题目非常相似,63题目只是在62的基础上,在地图上加入了障碍信息。其解答的过程告诉我们,当遇到一个很复杂的问题时,尝试去掉一些条件(简化问题),求得解之后,再去增加条件求解

棋类问题

  棋类等问题,通常可以用回溯法来解决。(见下面例子)

链表

1.链表访问 不具有跳跃性

假如你当前访问的结点为 N2, 那么接下来你 只能访问其相邻的结点 N1或者N3, 而不能不经过N3就直接跳去访问N4。换句话说,其访问的随机性小了(双链表情况下,下一次访问仍有两种选择)。

PS:

(1)随机性访问是数组的长处,你访问了A[2],接下来你可以访问A[3],也可以访问A[11]等,下一次访问的可以是任何数组中的元素。
(2)树的随机访问特性也是没有数组强的,但还是有一定的随机性的。(比如,二叉树中,当前节点为N,那么其下一个可能访问的结点为 N的两个孩子其中之一,每个有 1/2的概率)

2.链表访问具有方向性

(1)单链表只能向后访问
(2)链表构成队列本质上也是向后访问。(只不过插入时插到队列尾部,所以需要两个指针:头指针,用于出队;尾指针,用于入队。)
(3)链表构成的栈 本质上也是向后访问。(只不过限定每次插入都插入到头部位置,删除时先删除头)

PS:

(1)栈 与 队列都是建立在链表的基础之上的,只不过在链表插入时以及删除时做了一定的限制。
(2)有序性的数组可以使用二分查找,但不适合于有序性的链表。
(3)【有序性】在有序的基础上,可以方便很多操作(比如,二分查找,去重,统计某值出现次数)。

相关的题目

单个链表 + 更改操作

【单向性 + 计数后移】19. Remove Nth Node From End of List (也可以使用栈)

【单向性 + 反转】206. Reverse Linked List (可使用几个指针,或者使用栈)

【单向向后 + 限制反转】24. Swap Nodes in Pairs (只允许相邻(每两个)的反转)

单个链表 + 发现特殊结构
【链表 + 环结构判断】141. Linked List Cycle (链表中是否存在环?相关解答
【链表 + 环状判断】【启发】求有环单链表中的环长、环起点、链表长【快 、 慢指针】原来指针还可以有速度

多个链表

【单向向后 + 合并链表】21. Merge Two Sorted Lists(无论是数组还是链表都要求按序处理(N1之后是N2),那么在这方面数组与链表没有什么区别)

队列

  树或者图的广度优先遍历

特性

后进先出。

场景: 

(1)【次序】数据需要从后面向前匹配。

(2)【依赖】前面的数据的结果依赖于后面的数据。A(i) 结果依赖于 A(j),其中j > i ,且A(i)与其前面内容A(k)关系较少,其中i > k。(示例1:【栈】496. Next Greater Element I )(示例2:【栈 + 环形数组】 503. Next Greater Element II

(3) 将递归变为迭代。(示例:【树 + 栈 + 用迭代模拟递归】94. Binary Tree Inorder Traversal )(该问题有助于理解递归的计算机实现)

【启发 + 答案】94. Binary Tree Inorder Traversal(树的非递归中序遍历 + 栈模拟递归)

【树 + 栈 + 模拟先序遍历】144. Binary Tree Preorder Traversal

【树 + 栈 + 模拟后序遍历】145. Binary Tree Postorder Traversal

其他内容:

【队列 & 栈 + 互相模拟】 232. Implement Queue using Stacks

【队列 & 栈 + 互相模拟】 225. Implement Stack using Queues

【栈 + 括号匹配 + 就近匹配】20. Valid Parentheses括号的就近【向后】匹配原则,十分适用于通过栈来进行处理(使得出栈的规则变得简单)

树的应用十分广泛,它是一种数组 与链表之间的混合体。

(1)【和链表相似】是因为它的实现和链表的思想是一致的,这使得树具有链表的相似之处。

(2)【和数组相似】是因为在树中某个节点的孩子结点有多种可能(具有了部分数组的随机性),这使得它也可以做数组可做的事情(比如:二分查找)

注意

树的性质】不同的树往往具有不同的性质,而不同的性质导致了其不同的用途。所以有必要在练习的时候结合树的一些性质进行学习

遍历几乎所有树的操作都建立在遍历的基础之上。遍历分为 深度优先遍历 , 广度优先遍历。 — > 需要弄清楚这两种遍历方式适用的场景

深度优先遍历(应用场景)

先序遍历
(1) 当前结点的结果,后对孩子结点结果造成影响。(比如:【构建字符串 + 先序遍历】606. Construct String from Binary Tree

中序遍历
(1) 搜索树的遍历。(【寻找第k小 + 中序遍历(相当于从小到大访问) + 计数器(访问时计数)】230. Kth Smallest Element in a BST

后序遍历
(1) 当前结点的结果,依赖于其孩子结点的计算结果(比如:【二叉树的直径 + 自底向上(后序遍历)+ 技巧】543. Diameter of Binary Tree)

注意:

如果各结点独立,求解问题也不需要考虑次序,可使用任何一种遍历方式。

一棵树

针对树的遍历:

———– 非递归实现
先序遍历144. Binary Tree Preorder Traversal

中序遍历94. Binary Tree Inorder Traversal

后序遍历145. Binary Tree Postorder Traversal

———— 广度优先遍历
【广度 + 队列 + 计数(技巧)】637. Average of Levels in Binary Tree

遍历 + 目标:

【遍历 + 根到叶子的路径 +寻找规定的目标和】112. Path Sum

【遍历 + 根到叶子的路径 + 列出所有满足目标的路径】113. Path Sum II

【遍历 + 任一向下路径 + 寻找规定目标和 +计数 +技巧】437. Path Sum III

【平衡树判断 + 不一定是搜索树 + 高度计算 + 技巧】110. Balanced Binary Tree

【二叉树最大深度 + 自底向上(后序遍历) 】104. Maximum Depth of Binary Tree

【构建字符串 + 先序遍历】606. Construct String from Binary Tree

【计算所有左叶子结点的和】404. Sum of Left Leaves

【二叉树的直径 + 自底向上(后序遍历)+ 技巧】543. Diameter of Binary Tree(体会后序遍历的应用场景,当前结点的结果,依赖于其孩子结点的计算结果)

完全二叉树:
【高效计算完全二叉树的数量 + 利用完全二叉树的性质 + 技巧】222. Count Complete Tree Nodes

更改树
【反转二叉树 + 自顶向下(先序遍历) + 左右孩子交换】226. Invert Binary Tree

搜索树

更改搜索树
【删除二叉搜索树中的结点】450. Delete Node in a BST

【搜索树变为更大的树】538. Convert BST to Greater Tree

判断 & 寻找
【是否是二叉搜索树】98. Validate Binary Search Tree

【寻找第k小 + 中序遍历(相当于从小到大访问) + 计数器(访问时计数)】230. Kth Smallest Element in a BST

其他

【判断一颗树是否对称】101. Symmetric Tree

两棵树

【判断 2 树是否相同】 100. Same Tree

【按规则合并两棵二叉树】617. Merge Two Binary Trees

【判断一棵树是否是另一棵树的子树】572. Subtree of Another Tree

图类问题,一般需要记录访问状态(visited)

按照算法思想划分

数学相关

【百度百科】排列组合

计算几何题

复习几何问题的关键概念,然后尝试用编程思维去解决相关的问题。(做几道题,体会其关键思路
计算几何基础知识整理
【CSDN】计算几何题集

贪心法

分治法

动态规划

这篇文章给出了动态规划更具体的理解【总结】动态规划概述

动态规划 的核心是 分阶段决策
动态规划 在实现上,往往能够通过一定的技巧避免函数递归的出现

个人总结动态规划的特点:

按一定次序逼近目标】按照某种方式逐渐去接近目标。(逼近的方向应该是明确的,确保可以处理)

隔离性】动态规划通过划分想要达到的效果是,第 k 个阶段的求解,只与前面有限个阶段有关(如:只和第 k-1,k -2 个阶段有关)。这里也体现了分层次的思想(如,某一层只依赖于下面1层,且只能向上一层提供服务)。 —> 换句话说,你的划分角度应该能到隔离层次的目的。

【举例】上面特点的理解:

求连续子数组的最大和

连续区间问题

很多问题都可以归结为连续区间的问题。下面给出一些连续性区间问题的解答思路

不确定区间问题 转为 基于某种标准的坐标问题

加工问题,导出问题的子问题】《怎样解题》中提到的一种思想:(原则)将问题转化为类似的问题,以前见过的问题,而新的问题更加容易求解

示例:

leetcode - 303. Range Sum Query - Immutable 【动态规划 + 间接逼近目标 + 区间计算 +刻度 + 距离计算方式 】

试探法 + 及时舍去

这类问题,一个比较明显的特征是:【独立划分】在试探的过程中,如果某些条件不再符合,那么就采取剪枝的策略(也就是说,重新开始),之前的历史与后面的划分为无关的。可以通过下面一个例子体会:

最终的目标划分成小目标:(如,在求连续子数组最大和中,将原问题归结为求以每个数结尾的最大和)

远离目标时,及时终止;
接近目标时,继续使用。

求连续子数组的最大和
【启发】leetcode - 121. Best Time to Buy and Sell Stock 【动态规划 + 连续区间问题 + 试探性购买】 (这个问题可以归结成最大连续子数组的问题,细微的区别在于,(1)当远离目标时,终止的规则不同(利润重置为0);(2)其不是直接利用原来的数据,而是利用两个连续数之间的差(比最大连续子数组多了一步计算)

回溯法(VS 暴力法)

  回溯法又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。

回溯法解题的关键要素

(1) 针对给定的问题,定义问题的解空间
(2) 确定易于搜索的解空间结构
(3) 以深度优先方式搜索解空间,并且在搜索过程中用剪枝函数避免无效搜索

可结合如下问题进行体会:

基本实现

  • 递归 (在前面状态已经确定的情况下,探索下一个状态)
  • 状态记录
  • 回退(状态恢复)(到达回退点(需正确辨别)的时候,需要进行回退)

一些题库

UVA 题目难度分级列表

猜你喜欢

转载自blog.csdn.net/TheSnowBoy_2/article/details/77188448