Leetcode刷题思路

Leetcode刷题思路

  • 归纳法,如题628
  • 利用数学公式推理
  • hash表
    • 双hash表思想键值对调表查询
    • 键值对调
    • 利用hash表记录一些位置信息,然后通过if条件更新,比如题目:3
  • 链表
    • 反转链表"cppc"
    • 用哨兵节点方便控制一些逻辑,链表涉及到修改next要保存临时变量
    • 利用快慢指针优化链表遍历(快指针到底的时候,慢指针就是答案),比如题目:剑指 Offer 22
    • 直接指向下一个数就删除了,当然了也要把val给换了
    • 反转链表用到双指针加一个temp,也可以递归用两个参数两边来搞
  • 矩阵
    • 缓存思想的再可优化,比如题目1380
    • 解压压缩思路
    • 1572题:逐行算然后减去重叠的,双循环变 O{n} ,小心短路运算的坑,而且可以一次性对结果加两次妙,使用&1当0或者当1来计算妙啊
    int diagonalSum(vector<vector<int>>& mat) {
        int n = mat.size(), sum = 0, mid = n / 2;
        for (int i = 0; i < n; ++i) {
            sum += mat[i][i] + mat[i][n - 1 - i];
        }
        return sum - mat[mid][mid] * (n & 1);
    }

  • 脑筋急转弯

    • 反推思想,既然很多种情况都是为了达成某个目的,那么从这个目的入手,利用数学公式反推解决问题。
    • 整体思维法,不要成谜于解题步骤,从全局出发考虑问题。比如 657这道题
    • 替换思路,比如用数组模拟栈的一些特点,来解决问题,因为数组比栈直观,或者说更容易理解比如题目:1614
    • 反向思考问题,比如1688这道题:共有n个队伍,一个冠军,需要淘汰n-1个 队伍。每一场比赛淘汰一个队伍,因此进行了n-1场比赛。所以共有n-1个配对。
  • 回溯

    • 求幂集就是选择形成的n叉树

    在这里插入图片描述

  • 贪心算法

    • 转换思想,当某中计算过程过于复杂,转化成另外一问题来解决,而另外一种问题解决了就是最优答案了,因为贪心的理念也是当前最优的就可以了。
    • 转换思想再转换,把另一个问题转换为另另一个问题来解决,典型题1551.而且不一定非得构建题目条件中的数组,也可以解决问题还省空间
  • 位运算

    • 异或先求不同,再求解,其实就是一个转换的思想
    • i|=32大小写字母互相转换
    • 2进制转10进制,可以顺着乘以公式为ans = ans*2+0或1
    • 0 ^ x = x ; x ^ x = 0 ; 2x ^ (2x+1) = 1
    • a ^ b ^ b = a(这个交换的思路,其中运用到了临时变量)
    • a ^ b ^ a = b
    • 奇数&(-2)等于-1效果
    • 如果(n&1)==1,说明了n的尾巴是为1,如果一个数是2次幂,那么只有一个1其余全是0,形如:1,10,100,1000,10000
    • 如果位运算结果是0或1直接用于结算,不用判断了,比如题目:剑指 Offer 15
  • 数组

    • 把数组看成是一个环形
    • 用两个char相减来做数组的索引。
    • 两数组各元素进行异或、和,两个条件结合即可判断数组元素是否相同。
    • 单独拿一个数当max,用max做循环变量方便计算,比如题目5685
    • 用数组代替hash表,其中索引当作是key来对待
    • 前缀和思路
    • 储存下标的思路,让for循环减少一层,比如题1380
    • 遍历时候利用else重置flag状态
    • %运算解决循环问题
    • 利用求容器的长度,代替求差异,比如题1207
    • 1和10划分法,需要11种结果,那么先构造10种,然后以10种的和构造第11种
    • 当一个数组需要两种操作的时候,在循环筛选的时候同时做这两种操作,可以节省开销
    • 三重for循环,可以按条件提前剪枝
    • 数组划分一半
    • 数组项用完取负数拿来当标志
    • 前缀和思想,求区间之间的和,主要思想是开辟空间,记录这个下标之前的和,然后根据这个空间里面的两个数字相减就是其和,复杂度0{1}
    • 先排序再求解,排序后的位置可能还隐藏着更多帮助解题的信息,比如题目:1365
    • for迭代的既i++,又让i+=2,关键还对字符串直接修改呢
    • 局部判断失败就跳出,变量重置为0思想,这样的话一个变量重置了又可以判断其他的状态了,比如题目1662
    • 利用不对等式先化解一部分结论,然后根据这部分再来判断。
    • 迭代数目为原数组的一半思路
    • 利用一个数组的一些变量比如头节点做标志位,为了简洁
    • 题目1464:排序思路先排序就可以很少复杂度求出答案了,或者不排序一次遍历找出第一大和第二大的数(思路是先赋值first,再更新first,这样first就存的是第二大的数) 。下面是反面教材
  • 题目1603:让数组项通过自减和多信心存储,使得一个数组做了很多事情,很妙

  • 利用构造双倍加工集合长度的数组一次遍历思路,并且循环里面走两遍另起的index++

  • 构建26个字符数组思路

  • 字典

    • 利用字典优化双for循环,这代码实在是精妙
            Dictionary<int,int> dic=new Dictionary<int,int>();
            foreach(int i in nums)
            {
                if(dic.ContainsKey(i))
                {
                    dic[i]++;
                    res+=dic[i]-1;
                }
                else
                {
                    dic.Add(i,1);
                }
            }
  • 递归

    • 递归找到节点再添加,在递归中完成添加
    • 全排列需要记住三个状态,用过的,第几层了,path.
    • 递归中,重复设置容器的思路很赞啊,题目: 剑指 Offer 06
    • 位置变量先递进去,再进行运算,比如题目1290,不一定开头就带int计数,特别是有时候不知道计数是多少的时候。
    • 利用&&做递归短路出口,先递后归,逐渐完成加法,实在是妙啊
    • 只有一个出口不是在开头而是在末尾的写法
    • 和链表很配啊
  • 队列

    • 使用队列来模拟滑动窗口
    • 双栈或双队列
  • 双指针

    • 先排序
    • 快慢指针,一个走1步,一个走两步
    • 利用continue还有相等就push,不相等就pop的解题思路
    • 双栈或双队列
    • 遍历的过程中判断栈是否为空进行操作,而且if不是连起来的比如题目:1021
  • 数学

    • 等差数列求和公式:(n^2+n)/2
    • 整合思路:把多种步骤简化成一种公式,通过解数学公式,解开编程题如题目LCP17
    • 三元符替代Math.Max()
  • 字符串

    • 跳跃查找法,一次跳多格看看是否满足上下文比如题1309
    • KMP算法,1.做一个前缀表,2.在前缀表里面找最长相等前后缀,3.如果不匹配的那个字符查找前缀表,前缀表的值就是字符串要从0索引开始移动的位置。
    • 利用字符的asc码之间的计算公式转换成另一种问题来解决
    • 通过循环取模运算遍历字符每一个字符串,好处就是不用转换很多次哦。比如题目1281
    • 活用交换思想Swap,这样做到不开辟空间
    • 原地反转3次的思路,局部两次,整体一次
    • 遍历的的时候把i++,单独放在循环内部里
  • 滑动窗口

    • 只需要3个for循环就实现了,关键是for循环种下标的灵活运用,比如1588
  • 矩阵

    • 旋转物体中心点,并非坐标系轴哦
  • 动态规划

    • 分治思想并且把问题先转换成子问题,先求第一个子问题,在求第子问题过程中把真正问题解决了,从右向左递推。 经典题目53.最大子序和
  • 分治

    • 归并排序就是穿针引线的做法,包括两个排序链表的合并也是同理。
  • 复杂度分析

    • 最好
    • 最坏
    • 平均(涉及到概率学)
    • 均摊(一种更简单平均复杂度,每一次 O(n) 的插入操作,都会跟着 n-1 次 O(1) 的插入操作,所以把耗时多的那次操作均摊到接下来的 n-1 次耗时少的操作上,均摊下来,这一组连续的操作的均摊时间复杂度就是 O(1))
  • 排序算法

    • 基数(就是个位放几次,十位放几次,从上放进去,从下向上取出,可以使用队列)、计数(就是在排序磨具里统计数,再还原回去就好了)、桶排序 (类似哈希的策略,每个桶再单独排序)
  • 图算法

    • 深度优先遍历
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Grap : MonoBehaviour
{
    void Start()
    {
        var g = new Graph(new List<string>() {"1", "2", "3", "4", "5", "6", "7", "8"});
        g.SetEdge("1", "2");
        g.SetEdge("1", "3");

        g.SetEdge("2", "4");
        g.SetEdge("2", "5");
        g.SetEdge("2", "1");

        g.SetEdge("3", "1");
        g.SetEdge("3", "6");
        g.SetEdge("3", "7");


        g.SetEdge("4", "2");

        g.SetEdge("4", "8");

        g.SetEdge("5", "2");
        g.SetEdge("5", "8");

        g.SetEdge("6", "3");
        g.SetEdge("6", "7");

        g.SetEdge("7", "3");
        g.SetEdge("7", "6");

        g.SetEdge("8", "4");
        g.SetEdge("8", "5");


        g.ShowGraph();

        g.Dfs();
    }

    void Update()
    {
    }
}


public class Graph
{
    private List<string> Vertexs;
    private int[,] Matrix;
    private bool[] VisitedVertexIndex;

    public Graph(List<string> vertexs)
    {
        Vertexs = vertexs;
        int capacity = Vertexs.Count;
        Matrix = new int[capacity, capacity];
        VisitedVertexIndex = new bool[capacity];
    }

    private void VisitedVertex(int i)
    {
        Debug.Log("访问了:" + GetVertexVal(i));
        VisitedVertexIndex[i] = true;
    }

    private string GetVertexVal(int i)
    {
        return Vertexs[i];
    }

    public void Dfs()
    {
        for (int i = 0; i < Vertexs.Count; i++)
        {
            if (VisitedVertexIndex[i] == false)
            {
                dfs(i);
            }
        }
    }

    private void dfs(int startIndex)
    {
        VisitedVertex(startIndex);

        int w = FindFirstNeighborVertexIndex(startIndex);

        while (w!=-1)
        {
            if (VisitedVertexIndex[w]==false)
            {
                dfs(w);
            }

            w = FindNextNeighborVertexIndex(startIndex, w);
        }
        
    }

    /// <summary>
    /// 这里咱们的是不带权值的无向图
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <param name="val">0表示自己或者无法直接联通</param>
    private void SetEdge(int x, int y, int val)
    {
        Matrix[x, y] = val;
    }

    public void SetEdge(string self, string neighbor, int val = 1)
    {
        SetEdge(Vertexs.IndexOf(self), Vertexs.IndexOf(neighbor), val);
    }

    public void ShowGraph()
    {
        for (int i = 0; i < Matrix.GetLength(0); i++)
        {
            string lineStr = "";
            for (int j = 0; j < Matrix.GetLength(1); j++)
            {
                lineStr += Matrix[i, j] + "\t";
            }

            Debug.Log(lineStr);
        }
    }

    /// <summary>
    /// 查找第一个邻接点的,以x为key,y为值
    /// </summary>
    /// <returns></returns>
    public int FindFirstNeighborVertexIndex(int selfIndexX)
    {
        for (int i = 0; i < VisitedVertexIndex.Length; i++)
        {
            if (Matrix[selfIndexX, i] >0 )
            {
                return i;
            }
        }

        return -1;
    }

    public int FindNextNeighborVertexIndex(int selfIndex, int NextVertexIndexY)
    {
         for (int i = NextVertexIndexY+1; i < VisitedVertexIndex.Length; i++)
        {
            if (Matrix[selfIndex, i] > 0)
            {
                return i;
            }
        }

         return -1;
    }
}
*  矩阵模拟的迷宫图算法中有很多bool来做分支判断。
*   最小生成树(要在n个城市之间铺设光缆,主要目标是要使这 n 个城市的任意两个之间都可以通信,但铺设光缆的费用很高,且各个城市之间铺设光缆的费用不同,因此另一个目标是要使铺设光缆的总费用最低。这就需要找到带权的最小生成树)
* 拓扑排序(一个较大的工程往往被划分成许多子工程,我们把这些子工程称作活动(activity)。在整个工程中,有些子工程(活动)必须在其它有关子工程完成之后才能开始,也就是说,一个子工程的开始是以它的所有前序子工程的结束为先决条件的,但有些子工程没有先决条件,可以安排在任何时间开始。为了形象地反映出整个工程中各个子工程(活动)之间的先后关系,可用一个有向图来表示,图中的顶点代表活动(子工程),图中的有向边代表活动的先后关系,即有向边的起点的活动是终点活动的前序活动,只有当起点活动完成之后,其终点活动才能进行。通常,我们把这种顶点表示活动、边表示活动间先后关系的有向图称做顶点活动网(Activity On Vertex network),简称AOV网。)
* 求关键路径算法中带出 AOE网和AOV网的区别

AOV网:其顶点用来表示活动。AOE网是用来表示活动之间的制约关系。
AOE网:顶点表示事件,边表示活动,边上的权值用来表示活动持续的时间。AOV网是用来分析工程至少需要花多少时间完成,或是为了缩短时间需要加快哪些活动等问题。

    • 用数组模拟关键点
      • heapfly函数
      • S型向上heapfly函数
      • 堆排序时候,for循环不断减少做heapfly就完成排序了
    • 注意事项
      • 编写代码严谨性命名规范性,这些都能减少错误,争取一次bugFree不然浪费很长时间,int max =xx,后面就要用max去搞了
      • 索引公式p=(i-1)/2,c1=i2+1,c2=i2+2;
  • 二叉排序树
    • 中间二分开花,如题目108
    • 删除有3种情况
    • 中序遍历非递归的实现双重while循环,并且最外面一层while循环带两个bool判断
  • 矩阵
    • 把矩阵化成字典来求解
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值