Skip to content

jincc/iOS-Algorithm

Repository files navigation

leetcode顺序

 题号  题目链接             答案链接              难度   完成度 
1 两数之和 twoSum easy
2 两数相加 addTwoNumbers medium
3 无重复字符的最长子串 lengthOfLongestSubstring medium
5 最长回文子串 longestPalindrome medium [需要回看其他解法]
6 Z字形变换 zigzag_conversion medium
7 整数反转 reverse_integer easy
8 字符串转换整数 (atoi) string_to_integer_atoi medium
9 回文数 palindrome_number easy
11 盛最多水的容器 maxArea medium
12 整数转罗马数字 integer_to_roman medium
13 罗马数字转整数 romanToInt easy
14 最长功能前缀 longestCommonPrefix easy
15 三数之和 3sum medium
16 最接近的三数之和 3SumClosest medium
17 电话号码的字母组合 letter_combinations_of_a_phone_number medium
19 删除链表的倒数第N个节点 removeNthFromEnd medium
20 有限的括号 isValid easy
21 合并两个有序链表 mergeTwoLists easy
22 括号生成 generateParenthesis medium
24 两两交换链表中的节点 swapPairs medium
26 删除排序数组中重复项 removeDuplicates easy
27 移除元素 removeElement easy
28 实现 strStr() strStr easy
31 下一个排列 next_permutation medium
33 搜索旋转排序数组 searchInRotatedSortedArray medium
34 在排序数组中查找元素的第一个和最后一个位置 searchRange medium
35 搜索插入位置 searchInsert easy
36 有效的数独 isValidSudoku medium
39 组合总和 combinationSum medium
53 最大子序和 maxSubArray easy
58 最后一个单词的长度 lengthOfLastWord easy
66 加一 plusOne easy
67 二进制求和 addBinary easy
69 x 的平方根 mySqrt easy
70 爬楼梯 climbStairs easy
83 删除排序链表中的重复元素 deleteDuplicates easy
88 合并两个有序数组 merge easy
100 相同的树 isSameTree easy





下面按照具体的分类来刷题,总结每个思想的精髓。

算法思想

递归 🚶🚶🚶🚶

解决多阶段决策最优解模型的算法

解决问题的过程中,需要经过多个决策阶段,每个决策都会对应一个状态。我们寻找一组决策序列,经过这组决策序列,能够产生最终期望的最优值。我们把这种问题模型称为多阶段决策最优解模型. DP,回溯,贪心都可以解决这类问题.

利用动态规划解决的问题,需要满足三个特征:

  1. 最优子结构, 就是说后面的状态可以通过前面的状态推导出来
  2. 无后效性, 就是说一旦状态确定,就不会更改
  3. 重复子问题, 就是说不同的决策序列,到达某个相同的阶段时,可能会产生不同的状态。

贪心算法实际上是DP的一种特殊情况,它能解决的问题更加有限。需要满足三个条件:

  1. 最优子结构
  2. 无后效性
  3. 贪心选择性, 意思就是局部最优选择,能产生全局最优选择。

所以贪心算法能否解决算法问题的关键在于: 局部最优能不能达到全局最优?

回溯算法是”万金油“。基本上贪心和dp能解决的问题,回溯都能解决。回溯相当于穷举搜索,列举出所有的情况,然后对比得到最优解。不过回溯的复杂度一般都是指数级的,只能用来解决小规模数据的问题。






数据结构

数组有两个关键词:

  • 线性表结构, 就是说元素之间只有前后关系
  • 连续的内存空间,存储的是具有相同类型的数据

第二个特征决定了数组“随机访问”的能力,因为我们完全可以通过地址计算出下标对应的位置。比如:

a[i]_add = base_add + i * type_size

有利就有弊,也正是由于内存连续,所以数组的插入和删除是非常低效的,因为为了保持内存的连续,就意味着每次插入/删除都要伴随着大量的移动操作,平均负责度为o(n).

容器类在数组的基础上,封装了插入删除等操作,同时支持了动态扩容. 需要注意的是,如果实现知道数组的大小,最好提前指定容器大小,这样可以省掉多次的内存申请和数据搬移。

大多情况下的解题思路:

  • 双指针
  • DP
  • 二分查找