leetcode 刷题笔记一

本文精选了LeetCode上的多个经典算法题目,包括搜索旋转排序数组、子集生成、构建二叉树、寻找众数等,并提供了详细的解决方案及代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

leetcode81. Search in Rotated Sorted Array II
  1. 题目意思是:根据某个值旋转数组,在新的数组中查找某个元素
  2. 输入的数组可能是排好序的,也可能是排序之后旋转的
  3. 旋转数组由中间数划分:一定有一个区间是顺序的,判断target比这个区间最小数小,比最大数大,则不在该区间中,改变l或者r。

    public boolean search(int[] nums, int target) {    
        if(null == nums||nums.length==0) return false;    
        int l=0,r=nums.length-1;
        while(l<r){
            int m=(l+r)/2;
            if(nums[m]==target) return true;
            if(nums[l]<nums[r]){//没有旋转
                if(target>nums[m]){
                    l=m+1;
                }else{
                    r=m-1;
                }
            }else if(nums[l]>nums[r]){
               if(nums[m]>=nums[l]){
                   if(target>nums[m]||target<nums[l]) {
                       l=m+1;
                   }else{
                       r=m-1;
                   }
               }else{
                   if(target<nums[m]||target>nums[r]){
                       r=m-1;
                   }else{
                       l=m+1;
                   }
               }
            }else {
                l++;
            }
        }
        if(l==r && target==nums[l]) return true;
        else return false;
    } 
leetcode90. Subsets ||
  1. 题目要求列举出所有的集合情况
  2. 分成两类:集合中有重复元素 集合中没有重复元素
  3. 无重复元素:先产生一个空的数组,然后每次将新产生的元素放到已有的列表中
  4. 有重复元素:先排序,记录一下每次改变的list个数,如果当前元素与上一个元素重复,则仅改变上一次循环产生的list,否则就都要进行处理

    public List<List<Integer>> subsetsWithDup(int[] nums) {
        Arrays.sort(nums);
        List<List<Integer>> list= new ArrayList<List<Integer>>();
        List templist= new ArrayList<Integer>();
        list.add(new ArrayList<Integer>());
        templist.add(nums[0]);
        list.add(templist);
        int count=1;
        for(int j=1;j<nums.length;j++){
            int index=list.size();
            int start=0;
            if(nums[j]==nums[j-1]) {
                start=index-count;
            }
            count=0;
            for(int i=start;i<index;i++){
                List<Integer> temp =new ArrayList<Integer>(list.get(i));
                temp.add(nums[j]);
                list.add(temp);
                count++;
            }
        }
       return list;
    }
leetcode105,106 Construct Binary Tree
  1. 题目要求根据前序/后序和中序遍历,重新构建二叉树
  2. 用递归的方法,前序遍历中第一个位置就是根节点,然后在中序遍历中找根节点所在的位置,从而分出根节点的左右两边。
  3. 记录左右两边的开始和结束的位置,以及左右两边要找的下一个根节点
  4. 以前序遍历为例,左边的下一个根节点,就在当前节点+1,右边的下一个根节点,就是当前节点+(当前根节点位置-start)+1
root.left=buildHelper(preStart+1,start,index-1,preorder,inorder);```
root.right=buildHelper(preStart+index-start+1,index+1,end,preorder,inorder); 
leetcode 229. Majority Element(疑问:为什么c1,c2要减1)
  1. 题目要求将数组中出现次数大于1/3的数找出来
  2. 大于三分之一的数,一定少于等于2个,否则总数超过1
  3. 为了空间和时间的问题,设置两个数记录这两个数并用两个变量记录这两个数出现的次数
  4. 当前的数等于n1,则c1++;
  5. 当前的数等于n2,则c2++
  6. c1==0,则n1=当前数,c1=1
  7. c2==0.则n2=当前数,c2=1
  8. 否则 c1--,c2--
  9. 然后获得的n1,n2,就是出现最多的两个数,然后统计这两个数出现次数,若大于1/3,则添加到list中。

    public List<Integer> majorityElement(int[] nums) {
        List<Integer> list =new ArrayList<Integer>();
       if(null==nums||nums.length==0){
           return list;
       }
       int n=nums.length;
        if(n==1){
            list.add(nums[0]);
            return list;
        }
        int n1=nums[0];
        int n2=0;
        int c1=1,c2=0;
        for(int i=1;i<n;i++){
            if(nums[i]==n1){
                c1++;
            }else if(nums[i]==n2){
                c2++;
            }else if(c1==0){
                n1=nums[i];
                c1=1;
            }else if(c2==0){
                n2=nums[i];
                c2=1;
            }else{
                c1--;
                c2--;
            }
        }
        c1=0;
        c2=0;
        for(int i=0;i<n;i++){
            if(nums[i]==n1) c1++;
            else if(nums[i]==n2) c2++;
        }
        if(c1>n/3.0) list.add(n1);
        if(c2>n/3.0) list.add(n2);
        return list;
    }
leetcode 287. Find the Duplicate Number
  1. 根据题目特征,n+1个整数的范围在1-n中间
  2. 根据鸽巢原理,先统计1-n/2的数字出现次数,若大于一半,就认为有重复的数字,否则重复数字在另外一部分
  3. 用二分法来解决该问题
  4. 另一种算法flody判圈算法(该算法很重要,腾讯笔试题中曾出现)

    public int findDuplicate(int[] nums) {
        int start=1;
        int end=nums.length-1;
        int index=0;
        while(start<end){
            int count=0;
            index=(start+end)/2;
            for(int i=0;i<nums.length;i++){
                if(nums[i]<=index){
                    count++;
                }
            }
            if(count>index){
                end=index;
            }else{
                start=index+1;
            }
        }
        return start;
    }
leetcode 3. Longest Substring Without Repeating Charachters
  1. 总体思路确定起点,往后遍历,当遇到重复字符时,提取重复字符所在位置+1,为开始位置
  2. 当没有重复字符时,把当前字符存储到Map中

    public int lengthOfLongestSubstring(String s) {
        if (s.length()==0) return 0;
        HashMap<Character, Integer> map = new HashMap<Character, Integer>();
        int max=0;
        for (int i=0, j=0; i<s.length(); ++i){
            if (map.containsKey(s.charAt(i))){
                j = Math.max(j,map.get(s.charAt(i))+1);
            }
            map.put(s.charAt(i),i);
            max = Math.max(max,i-j+1);
        }
        return max;
    }
leetcode 15. 3sum(很好)
  1. 3个数相加,和需要为某一个值,重要的是考虑重复问题
  2. for循环从第一个元素遍历,后面就是2Sum问题
  3. 设置左右两个指针,如果当前元素与下一个元素相同,则i++
  4. 如果当前左右两个指针所指的数字和是目标值,就加入list,同时左右指针都往中间移动
  5. 每次循环过程中要判断左右两个指针前后是否有重复元素

    public List<List<Integer>> threeSum(int[] nums) {
       List<List<Integer>> list =new ArrayList<List<Integer>>();
        Arrays.sort(nums);
        for(int i=0;i<nums.length-2;i++){
            if(i>0&&nums[i]==nums[i-1]) {
                continue;
            }
            int target =-nums[i];
            int start=i+1,end=nums.length-1;
            while(start<end){
                if(nums[start]+nums[end]==target){
                    list.add(Arrays.asList(nums[i],nums[start],nums[end]));
                    start++;
                    end--;
                    while(start<end&&nums[start]==nums[start-1])start++;
                    while(start<end&&nums[end]==nums[end+1]) end--;
                }else if(nums[start]+nums[end]>target){
                    end--;
                }else{
                    start++;
                }
            }
        }
       return list;
    }
leetcode 5. Longest Palindromic Substring
  1. 给出字符串,找出最长的回文字串
  2. 方法有4种,暴力破解、动态规划、中心扩展、增加字符Manacher算法
  3. 暴力破解,遍历找出所有的子串,判断子串是否是回文字符串。时间复杂度为:n*n*n
  4. 动态规划:如果字符串sj是回文字符串,则(s+1,j-1)也是回文字符串。定义一个与字符串长度相同的二维数组,用来记录ij字符串是否是回文字符串。flag[i][i]一定为回文字符串,然后判断flag[i][i+1]是否是回文,再判断回文字符串长度大于等于3,以0起始位置开始,进行判断。时间复杂度为n*n
  5. 中心扩展方法:分奇数和偶数,都从i=0为中心点开始,奇数:s(i-1,i+1)相同,偶数s(i,i+1)相同,不断往外扩展。总体是一个for循环,里面一个while循环。时间复杂度为:n*n
  6. 为了解决中心扩展方法分奇偶的弊端,在字符串中间添加特殊字符,再以同样的方法遍历,时间复杂度为n

    public String longestPalindrome(String s) {
        if(null==s ||s.length()<=1) return s;
        int len =s.length();
        boolean [][] flag =new boolean[len][len];
        String result ="";
        int maxlen=1;
        int start=0;
        for(int i=0;i<len;i++){
            flag[i][i]=true;
          if(i<len-1&&s.charAt(i)==s.charAt(i+1)){
            flag[i][i+1]=true;
                maxlen=2;
             start=i;
           }
        }
        for(int i=3;i<=len;i++){
            for(int j=0;j<=len-i;j++){
                int end =j+i-1;
                if(s.charAt(j)==s.charAt(end)&&flag[j+1][end-1]==true){
                    flag[j][end]=true;
                    start=j;
                    maxlen=i;
                }
            }
        }
        if(maxlen>=2){
            return s.substring(start,start+maxlen);
        }else{
            return s.charAt(0)+"";
        }
    }
leetcode 19. Remove Nth Node From End of List
  1. 题目意思是:删除链表的倒数第n个数,且只能遍历一次,无法先遍历一遍获取链表的长度
  2. 设置两个指针,快指针先走n步,如果当时已经到末尾,则删除的就是第一个元素。否则就快慢指针一起走,直到快指针到达末尾后,慢指针当前的位置,就是倒数第n个元素的位置
  3. 使用 p.next = p.next.next来删除某个元素

    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode f =head;
        ListNode s =head;
        for(int i=0;i<n;i++){
            f=f.next;
        }
        while(f==null){
            head=head.next;
            return head;
        }
        while(f.next!=null){
            f=f.next;
            s=s.next;
        }
        s.next=s.next.next;
        return head;
    }
leetcode 22. Generate Parentheses
  1. 给出n个括号,写出所有的合法的括号组合
  2. 这个题跟验证合法性不同,运用的是深度优先算法dfs
  3. 即当左右两边括号数目都为0时,将当前的字符串加入list中。还要考虑左边大于右边的情况,这样直接返回
  4. 如果左边大于0,则添加(括号
  5. 如果右边大于0,则添加)括号

    public ArrayList<String> generateParenthesis(int n) {
        ArrayList<String> res = new ArrayList<String>();
        String item = new String();
        if (n<=0)
            return res;
        dfs(res,item,n,n);
        return res;
    }
    public void dfs(ArrayList<String> res, String item, int left, int right){
        if(left > right)//deal wiith ")("
            return;
        if (left == 0 && right == 0){
            res.add(new String(item));
            return;
        }
        if (left>0)
            dfs(res,item+'(',left-1,right);
        if (right>0)
            dfs(res,item+')',left,right-1);
    }
leetcode 31. Next Permutation
  1. 题目的意思是:给出一个数字序列,找出下一个比当前数字序列大的最小的排列
  2. 解决思路:从后往前找,如果当前数字比后面的数字小,则交换,同时将后面的数据进行升序排列,保证首先找到的数字一定是后面所有数字中最小的。
  3. 如果没有,则将当前位置开始到结尾的数字序列进行排序。两重for循环

    public void nextPermutation(int[] nums) {
        for(int i=nums.length-2;i>=0;i--){
            for(int j=i+1;j<nums.length;j++){
                if(nums[i]<nums[j]){
                    int temp=nums[i];
                    nums[i]=nums[j];
                    nums[j]=temp;
                    Arrays.sort(nums,i+1,nums.length);
                    return;
                }
            }
            Arrays.sort(nums,i,nums.length);
        }
    }
leetcode 94. Binary Tree Inorder Traversal
  1. 给一个二叉树,输出它的中序遍历
  2. 迭代的写法是:用栈的结构保存,先往左找到最底层的左叶子节点,然后把值添加到list中,然后开始遍历右边。
  3. 因为不熟悉树的遍历,所以值得学习

    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<Integer>();
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode cur =root;
        while(cur!=null || !stack.isEmpty()){
            while(cur!=null){
                stack.add(cur);
                cur = cur.left;
            }
            cur=stack.pop();
            list.add(cur.val);
            cur = cur.right;
        }
      return list;
    }
  4. 递归的方法

    public List < Integer > inorderTraversal(TreeNode root) {
        List < Integer > res = new ArrayList < > ();
        helper(root, res);
        return res;
    }
    public void helper(TreeNode root, List < Integer > res) {
        if (root != null) {
            if (root.left != null) {
                helper(root.left, res);
            }
            res.add(root.val);
            if (root.right != null) {
                helper(root.right, res);
            }
        }
    }
leetcode 96. Unique Binary Search Trees
  1. 题目:给出n个自然数,算出所有可能的二叉树结构数目
  2. 思路:G(n) = F(1,n)+F(2,n)+F(3,n)+…..+F(n,n)
  3. G(n)是n个数的二叉树个数,F(1,n)是以1为根节点总共n个节点的二叉树的数目
  4. F(i,n)=G(i-1)*G(n-i)
  5. 即G(n) =G(0)G(n-1)+G(1)G(n-2)+….+G(n-1)G(0)
  6. 使用递归的方法很简单,但是会超时
  7. 使用迭代的方法,用数组记录计算结果

    public int numTrees(int n) {
        int [] nums =new int [n+1];
        nums[0] = 1 ;
        nums[1] = 1 ;
        for(int i=2;i<=n;i++){
            for(int j=0; j<i ;j++){
                nums[i]=nums[i]+nums[j]*nums[i-j-1];
            }
        }
        return nums[n];
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值