解题-->在线OJ(十)

1.合并二叉树

在这里插入图片描述

解题思路:
如果两个结点都为空的话,直接返回空;
如果两个结点其中之一为空的话,直接返回一个不为空的结点;
如果两个结点都不为空的话,就新创建一个结点,新结点的值是两个结点值之和。

class Solution {
   public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        if(root1==null && root2==null){
            return null;
        }else if(root1==null || root2==null){
            return root1==null?root2:root1;
        }else{
            TreeNode temp=new TreeNode(root1.val+root2.val);
            temp.left=mergeTrees(root1.left,root2.left);
            temp.right=mergeTrees(root1.right,root2.right);
            return temp;
        }
    }
}

2.盛最多水的容器

在这里插入图片描述

解题思路:
双指针法:
定义两个变量,一个指向数组开头(left=0),一个指向数组最后一个位置(right=height.length-1),开始while循环,计算两个变量之间组成的面积,宽是两个变量之间的差值,高是取两个变量对应的数组元素的最小值。其中max代表组成的最大面积,max每次需要和算出来的面积进行比较,取出最大值。
如果左边(left)对应的数组元素小于等于right对应的数组元素,就将左边的(left)往右边挪一下,否则,右边(right)的往左挪一下。

class Solution {
       public int maxArea(int[] height) {
       int left=0;
       int right=height.length-1;
       int max=0;
       while(left<=right){
           int area=(right-left)*Math.min(height[left],height[right]);
           max=Math.max(area,max);
           if(height[left]<=height[right]){
               left++;
           }else{
               right--;
           }
       }
       return max;
    }
}

3.三数之和

在这里插入图片描述

解题思路:
1.先将数组进行排序;
2.从0下标开始遍历数组,left取i+1;right取nums.length-1,然后将三个下标对应的元素相加,最后结果值如果等于0,就将这三个下标所对应的元素借助Arrays.asList(),将这三个数组元素转换成一个list,加入到Set当中,Set集合框架提供HashSet类作为实现设置接口,这个特点就是:不添加重复元素。
3.如果三个下标对应的数组元素相加之后大于0,就证明right取大了,right下标需要往前挪一挪(right–);
4.相反,如果三个下标对应的数组元素相加之后小于0,就证明left取小了left下标需要往后挪一挪(left++)。

class Solution {
       public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);
        Set<List<Integer>> set=new HashSet<>();
        for(int i=0;i<nums.length;i++){
            int left=i+1;
            int right=nums.length-1;
            while(left<right){
                int temp=nums[left]+nums[right]+nums[i];
                if(temp==0){
                    set.add(Arrays.asList(nums[i],nums[left],nums[right]));
                    left++;
                    right--;
                }else if(temp>0){
                    right--;
                }else{
                    left++;
                }
            }
        }
        List<List<Integer>> list=new ArrayList<>();
        list.addAll(set);
        return list;
    }
}

4.电话号码的字母组合

用循环方式解决此题目:
1.先判断这个字符串是否为空,如果为空,就直接返回finalList即可;
2.字符串不为空的情况下,创建一个hashMap,来放这些不同的数字对应的字符串;
3.遍历这个字符串,先将finalList加一个“”,这个目的是:在第一次遍历的时候,finalList的size大小为0,就无法循环添加hashMap取出的字符串,所以,finalList.add(“”):这个目的是:使finalList的size大小为1;然后,调用add()方法,传参是:(finalList,hashMap.get(digit.charAt(i));
4.两层for循环,完成字符组合的操作。

class Solution {
     public  static List<String> letterCombinations(String digits) {
       List<String> finalList=new ArrayList<>();
       if("".equals(digits)){
           return finalList;
       }
       HashMap<Character,String> hashMap=new HashMap<>();
       hashMap.put('2',"abc");
       hashMap.put('3',"def");
       hashMap.put('4',"ghi");
       hashMap.put('5',"jkl");
       hashMap.put('6',"mno");
       hashMap.put('7',"pqrs");
       hashMap.put('8',"tuv");
       hashMap.put('9',"wxyz");
       finalList.add("");

       for(int i=0;i<digits.length();i++){
           finalList=add(finalList,hashMap.get(digits.charAt(i)));
       }
       return finalList;
    }
    public static List<String> add(List<String> list,String ret){
        List<String> newList=new ArrayList<>();
        for(int i=0;i<list.size();i++){
            for(int j=0;j<ret.length();j++){
                newList.add(list.get(i)+ret.charAt(j));
            }
        }
        return newList;
    }
}

5.删除链表的倒数第N个结点

在这里插入图片描述

第一种解题思路:
计算出链表的长度,链表需要走的长度是:temp=链表长度-n;
进入for循环i的初始值为0,i<temp,这个目的是:为了找到待删除结点的上一个结点。
退出循环后,将move.next=move.next.next;
再返回dummy.next即可。
这种方法的注意点:需要定义一个傀儡结点,让这个傀儡结点的下一个结点指向head;这个的目的是:如果待删除的结点是链表中的第一个结点。
2.在进入for循环之前,需要判定一下,结点为1个,n=1的这种情况,如果符合这种情况,返回null即可。这个的目的是为了防止后续move.next.next会出现空指针异常的情况。

class Solution {
    public static  ListNode removeNthFromEnd(ListNode head, int n) {
        //第一种解法:
        ListNode ret=new ListNode(-1);
        ret.next=head;
        ListNode move=ret;
        ListNode listNode=head;
        int length=countLength(listNode);
        int temp=length-n;
        if(length==1 && n==1){
            return null;
        }
        for(int i=0;i<temp;i++){
            move=move.next;
        }
        move.next=move.next.next;
        return ret.next;
    }
    public static int countLength(ListNode listNode){
        int length=0;
        while(listNode!=null){
            length++;
            listNode=listNode.next;
        }
        return length;
    }
}

第二种解题思路:栈
1.创建一个傀儡结点,让傀儡结点的下一个结点指向head;
2.创建一个栈,先遍历整个链表,让整个链表中的结点全部放在栈中,然后再for循环,i初始条件是:i=1;终止条件是:i<=n;然后,让栈中元素出栈;
3.退出循环之后,此时,栈顶元素是待删除结点的上一个结点,就可以直接让ret.next=ret.next.next;
4.返回dummy.next即可。

class Solution {
   public static  ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy=new ListNode(-1);
        dummy.next=head;
        Stack<ListNode> stack=new Stack<>();
        ListNode temp=dummy;
        while(temp!=null){
            stack.push(temp);
            temp=temp.next;
        }
        for(int i=1;i<=n;i++){
            stack.pop();
        }
        if(stack.isEmpty()){
            return null;
        }
        ListNode ret=stack.peek();
        ret.next=ret.next.next;
        return dummy.next;
    }
}

第三种解题思路:双指针
1.定义一个傀儡结点,让傀儡结点的下一个结点指向head;
2.定义两个变量,fast和slow,让fast走n步;
3.然后while循环,退出条件是fast.next!=null;在循环里面需要实现fast走一步,slow走一步;
4.当前退出循环后,slow指向的结点是待删除结点的上一个结点,所以,slow.next=slow.next.next;
5.返回dummy.next。

class Solution {
    public static  ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy=new ListNode(-1);
        dummy.next=head;
        ListNode fast=dummy;
        ListNode slow=dummy;
        for(int i=1;i<=n;i++){
            fast=fast.next;
        }
        while(fast.next!=null){
            fast=fast.next;
            slow=slow.next;
        }
        slow.next=slow.next.next;
        return dummy.next;
    }
}

6.括号生成

在这里插入图片描述

class Solution {
   List<String> ret=new ArrayList<>();
    public List<String> generateParenthesis(int n) {
        String s="";
        dfs(s,ret,n,n);
        return ret;
    }
    public static void dfs(String s,List<String> ret,int left,int right){
        if(left==0 && right==0){
            ret.add(s);
            return;
        }
        if(left>0){
            s+="(";
            dfs(s,ret,left-1,right);
            s=s.substring(0,s.length()-1);
        }
        if(right>left){
            s+=")";
            dfs(s,ret,left,right-1);
            s=s.substring(0,s.length()-1);
        }
    }
}

7.下一个排列

在这里插入图片描述

解题思路:
在这里插入图片描述

class Solution {
  public void nextPermutation(int[] nums) {
        if(nums==null || nums.length==0){
            return;
        }
        int j=nums.length-1;
        while(j>0){
            if(nums[j]<=nums[j-1]){
                j--;
            }else{
                int index=j-1;
                while(j<nums.length && nums[j]>nums[index]){
                    j++;
                }
                j--;
                int temp=nums[index];
                nums[index]=nums[j];
                nums[j]=temp;
                reverse(nums,index+1);
                return;
            }
        }
        reverse(nums,0);
    }
    public static void reverse(int[] nums,int index){
        int i=index;
        int j=nums.length-1;
        while (i<j){
            int temp=nums[i];
            nums[i]=nums[j];
            nums[j]=temp;
            i++;
            j--;
        }
    }
}

8.搜索旋转排序数组

在这里插入图片描述

解法一:
暴力求解法,从头到尾去遍历数组

class Solution {
   public int search(int[] nums, int target) {
        for(int i=0;i<nums.length;i++){
            if(target==nums[i]){
                return i;
            }
        }
        return -1;
    }
}

解法二:二分搜索
二分搜索法的前提是:基于有序的数组。
而这个题目,经过旋转之后,只有一半是有序的,是递增的。
在这个题目中,需要先判断 左边对应的元素 是否小于中间下标对应的元素,如果小于的话,就说明左边是有序的元素,则,判断target是否在左边的范围内,如果在,就递归调用,参数end改成mid-1;如果不在左边范围内,就递归调用,把参数start改成start+1;
对应右边也是这样的操作。

class Solution {
      public static int search(int[] nums, int target) {
        int start=0;
        int end=nums.length-1;
        int ret=FindIndex(nums,start,end,target);
        return ret;
    }
    public static int FindIndex(int[] nums,int start,int end,int target){
    if(start>end){
        return -1;
    }
        int mid=(start+end)/2;
        if(nums[mid]==target){
            return mid;
        }
        if(nums[start]==target){
            return start;
        }
        if(nums[end]==target){
            return end;
        }
       if(nums[start]<nums[mid]){
           if(nums[start]<target && target<nums[mid] ){
             return  FindIndex(nums,start,mid-1,target);
           }else{
             return  FindIndex(nums,mid+1,end,target);
           }
       }else{
           if(nums[mid]<target && target<nums[end]){
            return    FindIndex(nums,mid+1,end,target);
           }else{
            return    FindIndex(nums,start,mid-1,target);
           }
       }
    }
}

9.在排序数组中查找元素的第一个和最后一个位置

在这里插入图片描述

解题思路:
在这里插入图片描述

class Solution {
   public int[] searchRange(int[] nums, int target) {
        int[] index=new int[2];
        if(nums.length==0){
            return new int[]{-1,-1};
        }
        index[0]=FindLeft(nums,target);
        index[1]=FindRight(nums,target);
        return index;
    }
    public static int FindLeft(int[] nums,int target){
        int left=-1;
        int right=nums.length-1;
        while(left+1<right){
            int mid=(right+left)/2;
            if(nums[mid]<target){
                left=mid;
            }else{
                right=mid;
            }
        }
        if(nums[right]==target){
            return right;
        }
        return -1;
    }
    public static int FindRight(int[] nums,int target){
        int left=0;
        int right=nums.length;
        while(left+1<right){
            int mid=(left+right)/2;
            if(nums[mid]<=target){
                left=mid;
            }else{
                right=mid;
            }
        }
        if(nums[left]==target){
            return left;
        }
        return -1;
    }
}

10.组合总和

在这里插入图片描述

解题思路:
在这里插入图片描述

class Solution {
   List<List<Integer>> result=new ArrayList<>();
    List<Integer> list=new ArrayList<>();
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        Arrays.sort(candidates);
        int start=0;
        Find(candidates,start,target);
        return result;
    }
    public  void Find(int[] candidates,int start,int target){
        if(target==0){
            result.add(new ArrayList<>(list));
            return;
        }
        for(int i=start;i<candidates.length;i++){
            if(candidates[start]>target){
                break;
            }
            list.add(candidates[i]);
            Find(candidates,i,target-candidates[i]);
            list.remove(list.size()-1);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值