一、 双指针
- 普通双指针:两个指针往同一个方向移动(有时不是同一个方向)
- 对撞双指针:两个指针面对面移动
- 快慢双指针:慢指针+快指针
- 例:a = [1,4,5,7,9](有序数组) 两个数相加等于12,且两个数不能相同。
对撞双指针:
例:检测是否为环形链表
快慢双指针:慢指针每次循环移动一格,快指针移动两格,最终是否相遇。
public class Solution {
public boolean hasCycle(ListNode head) {
if(head == null){
return false;
}
else{
ListNode slow = head;
ListNode fast = head;
while(fast != null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
if (slow == fast){
return true;
}
}
return false;
}
}
}
class Solution:
def hasCycle(self, head: ListNode) -> bool:
if head == None:
return False
else:
slow = head
fast = head
while(fast != None and fast.next != None):
slow = slow.next
fast = fast.next.next
if slow == fast:
return True
return False
class Solution {
public int numRescueBoats(int[] people, int limit) {
Arrays.sort(people);
int low = 0,high = people.length-1,count = 0;
while(low<=high){
if(people[low]+people[high]>limit){
count += 1;
high -= 1;
}
else{
count += 1;
low += 1;
high -= 1;
}
}
return count;
}
}
class Solution:
def numRescueBoats(self, people: List[int], limit: int) -> int:
people.sort()
low = 0
high = len(people)-1
count = 0
while(low<=high):
if people[low]+people[high]>limit:
count += 1
high -= 1
else:
low += 1
high -= 1
count += 1
return count
二、 二分查找法
-
特点:一定要有序(数组元素单调增或单调减)
-
例题
class Solution {
public int search(int[] nums, int target) {
int low = 0,high = nums.length-1,mod;
while(low<=high){
mod = (low+high)/2;
if(nums[mod]== target) {
return mod;
}
else if(nums[mod]>target){
high = mod - 1;
}
else {
low = mod + 1;
}
}
return -1;
}
}
class Solution:
def search(self, nums: List[int], target: int) -> int:
low = 0
high = len(nums)-1
while(low<=high):
mod = (low+high)//2
if nums[mod] == target:
return mod
elif nums[mod]>target:
high = mod-1
else:
low = mod+1
return -1
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
if(matrix == null || matrix.length == 0){
return false;
}
else{
int row = matrix.length;
int col = matrix[0].length;
int l = 0;
int r = row*col-1;
while(l<=r){
int m = l+(r-l)/2;
int element = matrix[m/col][m%col];
if(element == target){
return true;
}
else if(element>target){
r = m-1;
}
else{
l = m+1;
}
}
return false;
}
}
}
class Solution:
def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
if matrix == None or len(matrix) == 0:
return False
else:
row = len(matrix)
col = len(matrix[0])
l = 0
r = row*col-1
while(l<=r):
m = l + (r-l)//2
element = matrix[m//col][m%col]
if element == target:
return True
elif element > target:
r = m-1
else:
l = m+1
return False
三、滑动窗口
-
目的:减少while循环
-
应用:数组中的定长问题
-
例题:
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int res = nums.length+1;
int i = 0,j = 0,total = 0;
while(j<nums.length){
total += nums[j];
while(total>=target){
res = Math.min(res, j - i + 1);
total -= nums[i];
i += 1;
}
j++;
}
if (res == nums.length+1){
return 0;
}
else{
return res;
}
}
}
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
res = len(nums)+1
count = 0
i = 0
j = 0
while(j<len(nums)):
count = count+nums[j]
while(count>=target):
res = min(res,j-i+1)
count = count - nums[i]
i = i+1
j+=1
if res == len(nums)+1:
return 0
else:
return res
class Solution {
public int maxVowels(String s, int k) {
int i,count = 0,res = 0;
char[] ch = s.toCharArray();
String str = "aeiou";
for (i = 0;i<k;i++){
if (str.indexOf(ch[i])!=-1){
count+=1;
}
}
res = Math.max(res,count);
for (i = k;i<s.length();i++){
if (str.indexOf(ch[i-k])!=-1){
count -= 1;
}
if (str.indexOf(ch[i])!=-1){
count += 1 ;
}
res = Math.max(res,count);
}
return res;
}
}
class Solution:
def maxVowels(self, s: str, k: int) -> int:
i = 0
count = 0
res = 0
for i in range(k):
if s[i] in "aeiou":
count+=1
res = max(res,count)
for i in range(k,len(s)):
if s[i-k] in "aeiou":
count -= 1
if s[i] in "aeiou":
count += 1
res = max(res,count)
return res
四、递归
-
定义:函数直接或者间接调用自己
-
四个要素:
- 接受的参数
- 返回值
- 终止条件
- 递归拆解:如何递归下一层
recursion(int n): #参数
if n == 0: #终止条件
return 0
m = recursion(n-1) #拆解
return m #返回的值
- 例题
class Solution {
public int fib(int n) {
if(n<2){
return n;
}
else{
return fib(n-1)+fib(n-2);
}
}
}
class Solution:
def fib(self, n: int) -> int:
if n<2:
return n
else:
sum = self.fib(n-1)+self.fib(n-2)
return sum
class Solution {
public ListNode reverseList(ListNode head) {
ListNode dummy = new ListNode(0);
dummy.next = head;
while(head != null && head.next != null){
ListNode dnext = dummy.next;
ListNode hnext = head.next;
dummy.next = head.next;
head.next = hnext.next;
hnext.next = dnext;
}
return dummy.next;
}
}
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
dummy = ListNode(0)
dummy.next = head
while(head != None and head.next!= None):
dnext = dummy.next
hnext = head.next
dummy.next = hnext
head.next = hnext.next
hnext.next = dnext
return dummy.next
五、分治法
大问题切割成一个个小问题,最后再合并。
用到了递归,自己调用自己。
class Solution:
def getNajority(nums,left,right):
if left == right:
return nums[left]
else:
mid = left+(right-left)//2
leftNajority = getNajority(nums,left,right)
rightNajority = getNajority(nums,mid+1,right)
if leftNajority == rightNajority:
return leftNajority
else:
leftcount = 0
rightcount = 0
for i in nums[left,right]:
if i == leftNajority:
leftcount+=1
elif i == rightNajority:
rightcount+=1
if leftcount > rightcount:
return leftNajority
else:
return rightNajority
def majorityElement(self, nums: List[int]) -> int:
return getNajority(nums,0,len(nums)-1)
六、回溯法
类似枚举,一层一层向下递归,尝试搜索答案。
- 找到答案后,尝试别的可能或返回答案。
- 找不到答案,则返回上一层递归,尝试别的路径。
七、深度优先搜索算法 (DFS)
- 用到了递归的思想。
- DFS:从root节点开始,尽可能深的搜索每一个分支。(把一个分支的结果搜索完,再去看下一个分支)
- 主要应用:
- 二叉树搜索
- 图搜索
- 例:走迷宫
- DFS和回溯算法的区别:回溯算法 = DFS + 剪枝
八、广度优先搜索算法(BFS)
- 主要思想:层层递进,一层一层遍历
- 主要应用:
- 二叉树搜索
- 图搜索
- DFS与BFS的区别:
侧重点不同:
- DFS:分支
- BFS:层
九、并查集(Union Find)
- Union:合并两个元素为同一个根节点
- Find:找到某个元素的根节点
十、贪心算法(Greedy)
- 核心:
- 每一步做出的都是当前看起来最好的选择
- 只是局部的最优选择
- 而不是整体的最优选择
- 例:零钱兑换 最少硬币的情况,应当尽可能取大的硬币
十一、算法记忆化(Memoization)
- 目的:减少重复计算
十二、动态规划
- 题型千变万化
- 思想千变万化
动态规划三要素:
- 初始状态(可能是一个数,也可能是多个数)
- 方程式(状态转移函数)
- 终止状态
应用:
- 计数:有多少种方式/方法
例:机器人从左上角到右下角有多少个路径 - 求最值:最大值/最小值
例:机器人从左->右路径的最大数字和 - 求存在性:是否存在某个可能
例:是否存在机器人从左->右的路径
class Solution {
public int fib(int n) {
if(n<2){
return n;
}
else{
int dp[] = new int[n+1];
dp[0] = 0;
dp[1] = 1;
for(int i=2;i<n+1;i++){
dp[i] = dp[i-1] + dp[i-2];
}
return dp[n];
}
}
}
class Solution {
public int uniquePaths(int m, int n) {
int [][] dp =new int[m][n];
dp[0][0] = 1;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(i-1>=0 && i-1<m){
dp[i][j] = dp[i][j]+dp[i-1][j];
}
if(j-1>=0 && j-1<n){
dp[i][j] = dp[i][j]+dp[i][j-1];
}
}
}
return dp[m-1][n-1];
}
}