常用算法规整


常用的算法总结

数组 模块

两数之和

1 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1]

示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]

示例 3:

输入:nums = [3,3], target = 6
输出:[0,1]

class Solution {
    public int[] twoSum(int[] nums, int target) {
            HashMap map= new HashMap<Integer,Integer>();
            int[] arr=new int[2];
            for(int i=0;i<nums.length;i++){
                map.put(nums[i],i);
            }

            for(int i=0;i<nums.length;i++){
                int targetNum= target-nums[i];
                if(map.get(targetNum)!=null&&(int)map.get(targetNum)!=0){
                    if(i!=(int)map.get(targetNum)){
                    arr[0]=i;
                    arr[1]=(int)map.get(targetNum);
                    break;
                    }
                }]
            }
        return arr;
    }
}

盛最多水的容器
2 给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

示例 1

输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

示例 2:

输入:height = [1,1]
输出:1

示例 3:

输入:height = [4,3,2,1,4]
输出:16

示例 4:
输入:height = [1,2,1]
输出:2

class Solution {
    public int maxArea(int[] height) {
        int start=0;
        int end=height.length-1;
        int maxArea=0;
        while(start<end){

            if(height[start]<height[end]){
              int max=  (end-start)*height[start];
                if(maxArea<max){
                    maxArea=max;
                }
                start++;
            }else{
                int max=  (end-start)*height[end];
                if(maxArea<max){
                    maxArea=max;
                } 
                end--;
            }
        }

        return maxArea;
    }
}

三数之和

3 给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]

示例 2:

输入:nums = []
输出:[]

示例 3:

输入:nums = [0]
输出:[]


class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
           ArrayList<List<Integer>> integers = new ArrayList<>();
        if (nums == null || nums.length < 3) {
            return integers;
        }

        Arrays.sort(nums);

        for (int i = 0; i < nums.length - 2; i++) {
            if (nums[i] > 0) {
                break;
            }

            if (i > 0 && nums[i] == nums[i - 1]) continue; //去掉重复的情况 因为前面排序了 隔壁一样就是一样重复的

            int target = -nums[i];
            int left = i + 1, right = nums.length - 1;

            while (left < right) {
                if (nums[left] + nums[right] == target) {
                    integers.add(new ArrayList<Integer>(Arrays.asList(nums[i], nums[left], nums[right])));
                    left++;
                    right--;
                    while (left<right&&nums[left]==nums[left-1]){
                        left++;
                    }
                    while (left<right&&nums[right]==nums[right+1]){
                        right--;
                    }

                } else if (nums[left] + nums[right] < target) {
                    left++;
                } else {
                    right--;
                }
            }

        }
        return integers;
    }
}

组合总和
给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。

candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。 

对于给定的输入,保证和为 target 的不同组合数少于 150 个。

示例 1:

输入:candidates = [2,3,6,7], target = 7
输出:[[2,2,3],[7]]
解释:
2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。
7 也是一个候选, 7 = 7 。
仅有这两种组合。

示例 2:

输入: candidates = [2,3,5], target = 8
输出: [[2,2,2,2],[2,3,3],[3,5]]

示例 3:

输入: candidates = [2], target = 1
输出: []

class Solution {
        List<List<Integer>> res;

    public List<List<Integer>> combinationSum(int[] candidates, int target) {
         res=new ArrayList<>();
         Arrays.sort(candidates);
       ArrayList<Integer> path =new ArrayList();
        backTrace(candidates,target,path,0); //采用回溯递归的方式
         return res;
    }

    private void backTrace(int[] candidates,int target,ArrayList<Integer> path, int start ){

            if(target==0){ //如果等于0 那么这个组合就是满足条件的 可以加入
                res.add(new ArrayList(path));
                return; 
            }

            for(int i=start;i<candidates.length;i++){//对根树来说的
                    if(candidates[i]>target){ //如果当前都大于目标 那么就说明没有这个组合了因为 target会累加
                        return;
                    }
                    path.add(candidates[i]);//将这个路径放进去
                    backTrace(candidates,target-candidates[i],path,i);//判断这个路径相减  然后要注意i是起始的意思  有这个start的话可以做到不考虑前面的数组,注意 因为是递归也就是从树的根部开始算起的,根节点触发的才不能用前面的树 也就是说第一轮for遍历是对根数组来说的,剩下的是底部数组
                
                    path.remove(path.size()-1);//删除的是顶部的那个,这样才会回溯的效果 类似于最底部的删除重新尝试

            }
    }



}

螺旋矩阵

4 给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]

输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]


class Solution {
    public List<Integer> spiralOrder(int[][] matrix) {
        int  left=0;
        int  right=matrix[0].length-1;
        int top=0;
        int bottom=matrix.length-1;
        List<Integer> list=new ArrayList<Integer>();


        while(right>left&&bottom>top){

         for(int i=left;i<=right;i++){
                list.add(matrix[top][i]);
        }

          top++;  

        for(int i=top;i<=bottom;i++){
            list.add(matrix[i][right]);
        }
        right--;

        for(int i=right;i>=left;i--){
            list.add(matrix[bottom][i]);
        }    
        bottom--;

        for(int i=bottom;i>=top;i--){
            list.add(matrix[i][left]);
        }
        left++;

        }
        if(left<right&&top==bottom){
            for(int i=left;i<=right;i++){
                list.add(matrix[top][i]);
            }
        }

        if(top<bottom&&left==right){
            for(int i=top;i<=bottom;i++){
                list.add(matrix[i][left]);
            }
        }
        if(left==right&&top==bottom){
            list.add(matrix[top][left]);
        }

        return list;
    }
}

合并区间

5 以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。

示例 1:

输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].

示例 2:

输入:intervals = [[1,4],[4,5]]
输出:[[1,5]]
解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。

class Solution {
    public int[][] merge(int[][] intervals) {
            Arrays.sort(intervals,new Comparator<int[]>(){
                public int compare(int[] interval1,int[] interval2){
                    return interval1[0]-interval2[0];
                }
            });

            ArrayList<int[]> list=new ArrayList<int[]>();

            for(int i=0;i<intervals.length;i++){
                int L=intervals[i][0];
                int R=intervals[i][1];
                if(list.size()==0||list.get(list.size()-1)[1]<L){
                    list.add(new int[]{L,R});
                }else{
                 
                    list.get(list.size()-1)[1]=Math.max(list.get(list.size()-1)[1],R);   
                }

            }

            return list.toArray(new int[list.size()][]);
    }
}

最小路径和

6 给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

说明:每次只能向下或者向右移动一步。

输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
输出:7
解释:因为路径 1→3→1→1→1 的总和最小。

输入:grid = [[1,2,3],[4,5,6]]
输出:12


class Solution {
    public int minPathSum(int[][] grid) {
        int m=grid.length;
        int n=grid[0].length;


        int[][] arr=new int[m][n];

        arr[0][0]=grid[0][0];
        for(int i=1;i<n;i++){
            arr[0][i]=arr[0][i-1]+grid[0][i];
        }

        for(int i=1;i<m;i++){
            arr[i][0]=arr[i-1][0]+grid[i][0];
        }


        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                arr[i][j]=Math.min(arr[i-1][j],arr[i][j-1])+grid[i][j];
            }
        }

        return arr[m-1][n-1];

    }
}

子集

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

示例 1:

输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

示例 2:

输入:nums = [0]
输出:[[],[0]]


class Solution {
    public List<List<Integer>> subsets(int[] nums) {

       List<List<Integer>> res = new ArrayList<>();
        res.add(new ArrayList());
        for(int i=0;i<nums.length;i++){
            int all =res.size();
             System.out.print(all);

            for(int j=0;j<all;j++){
                    List<Integer> tmp=new ArrayList<>(res.get(j));
                        tmp.add(nums[i]);
                        res.add(tmp);
            }
        }
        return res;

    }
}

合并两个有序数组

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。

请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。

注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

示例 1:

输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。

示例 2:
输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]
解释:需要合并 [1] 和 [] 。
合并结果是 [1] 。

示例 3:

输入:nums1 = [0], m = 0, nums2 = [1], n = 1
输出:[1]
解释:需要合并的数组是 [] 和 [1] 。
合并结果是 [1] 。
注意,因为 m = 0 ,所以 nums1 中没有元素。nums1 中仅存的 0 仅仅是为了确保合并结果可以顺利存放到 nums1 中。

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
            if(n==0){
                return;
            }

           if(m==0){
                for(int i=0;i<n;i++){
                    nums1[i]=nums2[i];
                }
            }

            for(int i=m;i<m+n;i++){
                nums1[i]=nums2[i-m];
            }
        
            
            Arrays.sort(nums1);
    

    }
}

将有序数组转换为二叉搜索树

给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。

高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。

输入:nums = [-10,-3,0,5,9]
输出:[0,-3,9,-10,null,5]
解释:[0,-10,5,null,-3,null,9] 也将被视为正确答案:

输入:nums = [1,3]
输出:[3,1]
解释:[1,3] 和 [3,1] 都是高度平衡二叉搜索树


/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
            if(nums==null){
                return null;
            }

          return  getMidTree(nums,0,nums.length-1);

    }

    public TreeNode getMidTree(int[] nums,int left,int right){
        if(left>right){
            return null;
        }
        int mid=left+(right-left)/2;
        System.out.print("mid:"+nums[mid]);
       TreeNode tree= new TreeNode(nums[mid]);

       tree.left=getMidTree(nums,left,mid-1);
       tree.right=getMidTree(nums,mid+1,right);

        return tree;
    }

 
}

买卖股票的最佳时机

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

示例 1:

输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

示例 2:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。


class Solution {
    public int maxProfit(int[] prices) {
            int maxValue=0;
            int min=Integer.MAX_VALUE;

            for(int i=0;i<prices.length;i++){
                min=Math.min(min,prices[i]);
                int tempValue= prices[i]-min;
                maxValue=Math.max(maxValue,tempValue);                
            }
            return maxValue;
            
    }
}

买卖股票的最佳时机 II

给定一个数组 prices ,其中 prices[i] 表示股票第 i 天的价格。

在每一天,你可能会决定购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以购买它,然后在 同一天 出售。
返回 你能获得的 最大 利润 。

示例 1:

输入: prices = [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
  随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3

示例 2:

输入: prices = [1,2,3,4,5]
输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
  注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。

示例 3:

输入: prices = [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

class Solution {
    public int maxProfit(int[] prices) {
        int maxValue=0;
        for(int i=prices.length-1;i>0;i--){
            if(prices[i]>prices[i-1]){
                maxValue+=prices[i]-prices[i-1];
            }
        }
        return maxValue;
    }
}

最长连续序列

给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。

请你设计并实现时间复杂度为 O(n) 的算法解决此问题。

示例 1:
输入:nums = [100,4,200,1,3,2]
输出:4
解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。

示例 2:

输入:nums = [0,3,7,2,5,8,4,6,0,1]
输出:9



class Solution {
    public int longestConsecutive(int[] nums) {
            if(nums==null||nums.length==0){
                return 0;
            }

            Arrays.sort(nums);

            for(int i=0;i<nums.length;i++){
                System.out.print(nums[i]);
            }
        
            int maxLength=1;
            int finalMax=1;

            for(int i=0;i<nums.length-1;i++){
                if(nums[i+1] - nums[i]==1){
                    maxLength++;
                }else if(nums[i+1]-nums[i]==0){
                    continue;
                }else{
                    finalMax= Math.max(maxLength,finalMax);
                    maxLength=1;
                }
            }
            finalMax= Math.max(maxLength,finalMax);

            return finalMax;
    }
}

只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

说明:

你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

示例 1:

输入: [2,2,1]
输出: 1
示例 2:

输入: [4,1,2,1,2]
输出: 4


class Solution {
    public int singleNumber(int[] nums) {
        HashMap map=new HashMap<Integer,Integer>();

        for(int i=0;i<nums.length;i++){
                if(map.get(nums[i])!=null){
                    map.put(nums[i],(int)map.get(nums[i])+1);
                }else{
                    map.put(nums[i],1);
                }
        }
       Set<Integer> sets= map.keySet();
        for(Integer key: sets){
            if((int)map.get(key)==1){
                return key;
            }
        }

            return -1;
    }
}

只出现一次的数字 II

给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。

 

示例 1:

输入:nums = [2,2,3,2]
输出:3
示例 2:

输入:nums = [0,1,0,1,0,1,99]
输出:99  

提示:

1 <= nums.length <= 3 * 104
-231 <= nums[i] <= 231 - 1
nums 中,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次


class Solution {
    public int singleNumber(int[] nums) {
        //搞一个集合来存储
        HashMap map=new HashMap<Integer,Integer>();


        //遍历将数据存进去 map
        for(int i=0;i<nums.length;i++){
            if(map.get(nums[i])==null){
                map.put(nums[i],1);
            }else{
                map.put(nums[i],(int)map.get(nums[i])+1);
            }
        }
//      遍历map 如果存在一个值为1的话 那么就返回
        Set<Integer> sets=map.keySet();
        for(Integer key:sets){
            if((int)map.get(key)==1){
                return key;
            }
        }


        return 0;

    }
}

乘积最大子数组

给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。

 

示例 1:

输入: [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
示例 2:

输入: [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。


class Solution {
    public int maxProduct(int[] nums) {
        if(nums==null){
            return 0;
        }
        if(nums.length==0){
            return nums[0];
        }

        int max=Integer.MIN_VALUE;
        int  imax=1;
        int  imin=1;
    


        for(int i=0;i<nums.length;i++){
            if(nums[i]<0){
                int tmp=imax;
                imax=imin;
                imin=tmp;
            }

            imax=Math.max(imax*nums[i],nums[i]);
            imin=Math.min(imin*nums[i],nums[i]);
            max=Math.max(max,imax);
        }
        return max;

    }
}

峰值元素是指其值严格大于左右相邻值的元素。

给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。

你可以假设 nums[-1] = nums[n] = -∞ 。

你必须实现时间复杂度为 O(log n) 的算法来解决此问题。

 

示例 1:

输入:nums = [1,2,3,1]
输出:2
解释:3 是峰值元素,你的函数应该返回其索引 2。
示例 2:

输入:nums = [1,2,1,3,5,6,4]
输出:1 或 5
解释:你的函数可以返回索引 1,其峰值元素为 2;
  或者返回索引 5, 其峰值元素为 6。

class Solution {
    public int findPeakElement(int[] nums) {
        if(nums.length==1||nums.length==0){
            return 0;
        }

        if(nums.length==2){
            if(nums[0]>nums[1]){
                return 0;
            }else{
                return  1;
            }
        }


            

            for(int i=1;i<nums.length-1;i++){
                if(nums[i]>nums[i-1]&&nums[i]>nums[i+1]){
                    return i;
                }
            }

             if(nums[nums.length-1]>nums[nums.length-2]){
                    return nums.length-1;
                }




        return 0;
    }
}

轮转数组

给你一个数组,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

 

示例 1:

输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1 步: [7,1,2,3,4,5,6]
向右轮转 2 步: [6,7,1,2,3,4,5]
向右轮转 3 步: [5,6,7,1,2,3,4]
示例 2:

输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
解释:
向右轮转 1 步: [99,-1,-100,3]
向右轮转 2 步: [3,99,-1,-100]


class Solution {
    public void rotate(int[] nums, int k) {
        
            //求余数为了避免k大于nums
            k=k%nums.length;


            //这个是为了放在前面
           ArrayList<Integer> firstList= new ArrayList<Integer>();    
           //这个是为了放在后面
           ArrayList<Integer> secondList= new ArrayList<Integer>();    

            //这个把后面的切割下来
            for(int i=nums.length-1;i>=nums.length-k;i--){
                firstList.add(nums[i]);
            }


            // 这个添加到后面
            for(int i=0;i<nums.length-k;i++){
                secondList.add(nums[i]);
            }
            
            for(int i=0;i<firstList.size();i++){
                nums[i]=firstList.get(firstList.size()-i-1);
            }

            for(int i=0;i<secondList.size();i++){
                nums[i+firstList.size()]=secondList.get(i);
            }

    }
}

岛屿数量

给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。

 

示例 1:

输入:grid = [
[“1”,”1”,”1”,”1”,”0”],
[“1”,”1”,”0”,”1”,”0”],
[“1”,”1”,”0”,”0”,”0”],
[“0”,”0”,”0”,”0”,”0”]
]
输出:1
示例 2:

输入:grid = [
[“1”,”1”,”0”,”0”,”0”],
[“1”,”1”,”0”,”0”,”0”],
[“0”,”0”,”1”,”0”,”0”],
[“0”,”0”,”0”,”1”,”1”]
]
输出:3  

提示:

m == grid.length
n == grid[i].length
1 <= m, n <= 300
grid[i][j] 的值为 ‘0’ 或 ‘1’

class Solution {
    int  count=0;
    public int numIslands(char[][] grid) {
        //判空
        if(grid[0].length==0||grid.length==0){
            return 0;
        }
        //拿出这个矩阵的横和列
        int right=grid[0].length;
        int bottom=grid.length;
        //
        for(int i=0;i<bottom;i++){
            for(int j=0;j<right;j++){
                //遍历整个矩阵 如果发现有一个是1的开启深度搜索 找到后给这个计数器加一
                if(grid[i][j]=='1'){
                    dfs(grid,i,j);
                    count++;
                }
            }
        }
        return count;
    }
    //深度邮箱搜索
    public void dfs(char[][] grid,int i,int j){
        //关键就是这个判断标准,超出不可以 为0不可以
        if(i<0||i>grid.length-1||j<0||j>grid[0].length-1||grid[i][j]=='0'){
            return;
        }
        //递归调用了上下左右,这个方法结束的时候就一个岛屿
        grid[i][j]='0';
        dfs(grid,i-1,j);
        dfs(grid,i+1,j);
        dfs(grid,i,j-1);
        dfs(grid,i,j+1);

    }
}

最大正方形

在一个由 ‘0’ 和 ‘1’ 组成的二维矩阵内,找到只包含 ‘1’ 的最大正方形,并返回其面积。

 

示例 1:
输入:matrix = [[“1”,”0”,”1”,”0”,”0”],[“1”,”0”,”1”,”1”,”1”],[“1”,”1”,”1”,”1”,”1”],[“1”,”0”,”0”,”1”,”0”]]
输出:4

示例 2:

输入:matrix = [[“0”,”1”],[“1”,”0”]]
输出:1

示例 3:
输入:matrix = [[“0”]]
输出:0


class Solution {
    public int maximalSquare(char[][] matrix) {
        int maxSide = 0;
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
            return maxSide;
        }
        int rows = matrix.length, columns = matrix[0].length;
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < columns; j++) {
                if (matrix[i][j] == '1') {
                    // 遇到一个 1 作为正方形的左上角
                    maxSide = Math.max(maxSide, 1);
                    // 计算可能的最大正方形边长
                    int currentMaxSide = Math.min(rows - i, columns - j);
                    for (int k = 1; k < currentMaxSide; k++) {
                        // 判断新增的一行一列是否均为 1
                        boolean flag = true;
                        if (matrix[i + k][j + k] == '0') {
                            break;
                        }
                        for (int m = 0; m < k; m++) {
                            if (matrix[i + k][j + m] == '0' || matrix[i + m][j + k] == '0') {
                                flag = false;
                                break;
                            }
                        }
                        if (flag) {
                            maxSide = Math.max(maxSide, k + 1);
                        } else {
                            break;
                        }
                    }
                }
            }
        }
        int maxSquare = maxSide * maxSide;
        return maxSquare;
    }
}

最长递增子序列

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

 
示例 1:

输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
示例 2:

输入:nums = [0,1,0,3,2,3]
输出:4
示例 3:

输入:nums = [7,7,7,7,7,7,7]
输出:1  

提示:

1 <= nums.length <= 2500
-104 <= nums[i] <= 104


class Solution {
    public int lengthOfLIS(int[] nums) {
           if(nums.length<=1){
               return nums.length;
           }
           int n=nums.length;
            int arr[]=new int[n];
            for(int i=0;i<nums.length;i++){
                arr[i]=1;
            }

            int result=1;
            for(int i=0;i<nums.length;i++){
                    for(int j=0;j<i;j++){
                        if(nums[i]>nums[j]){
                        arr[i]=Math.max(arr[i],arr[j]+1);
                        }
                    }
                   result=Math.max(arr[i],result); 
            }

            return result;
    }
}

零钱兑换

给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。

计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。

你可以认为每种硬币的数量是无限的。

示例 1:

输入:coins = [1, 2, 5], amount = 11
输出:3
解释:11 = 5 + 5 + 1

示例 2:

输入:coins = [2], amount = 3
输出:-1

示例 3:

输入:coins = [1], amount = 0
输出:0


class Solution {
    public int coinChange(int[] coins, int amount) {
        int max = Integer.MAX_VALUE;
        int[] dp = new int[amount + 1];
        //初始化dp数组为最大值
        for (int j = 0; j < dp.length; j++) {
            dp[j] = max;
        }
        //当金额为0时需要的硬币数目为0
        dp[0] = 0;
        for (int i = 0; i < coins.length; i++) {
            //正序遍历:完全背包每个硬币可以选择多次
            for (int j = coins[i]; j <= amount; j++) {
                //只有dp[j-coins[i]]不是初始最大值时,该位才有选择的必要
                if (dp[j - coins[i]] != max) {
                    //选择硬币数目最小的情况
                    dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1);
                }
            }
        }
        return dp[amount] == max ? -1 : dp[amount];
        //这道题还不是很懂
    }
}

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。  

前 K 个高频元素

示例 1:

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:

输入: nums = [1], k = 1
输出: [1]  

提示:

1 <= nums.length <= 105
k 的取值范围是 [1, 数组中不相同的元素的个数]
题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        HashMap<Integer,Integer> map=new HashMap<Integer,Integer>();
        //遍历将出现的次数和值放到一个map中
            for(int i=0;i<nums.length;i++){
                if(map.get(nums[i])==null){
                    map.put(nums[i],1);
                }else{
                    map.put(nums[i],(int)map.get(nums[i])+1);
                }
            }

         
            //这个是一个关键 对一个包着map的list进行排序
              List<Map.Entry<Integer,Integer>> list=new ArrayList<>(map.entrySet());
            // 如果b值大于a值那么就排前面
                Collections.sort(list,(a,b)->{
                    return b.getValue()-a.getValue();
                });

            //最后遍历 就拿前面k个值
                int[] arr=new int[k];
                for(int i=0;i<k;i++){
                    arr[i]=(int)list.get(i).getKey();
                }
        return arr;
    }
}

三个数的最大乘积

给你一个整型数组 nums ,在数组中找出由三个数组成的最大乘积,并输出这个乘积。

 

示例 1:

输入:nums = [1,2,3]
输出:6
示例 2:

输入:nums = [1,2,3,4]
输出:24
示例 3:

输入:nums = [-1,-2,-3]
输出:-6

class Solution {
    public int maximumProduct(int[] nums) {
            int max=Integer.MIN_VALUE;
            if(nums==null||nums.length==0){
                return 0;
            }
            if(nums.length==1){
                return nums[0];
            }
            if(nums.length==2){
                return nums[1]*nums[0];
            }

            Arrays.sort(nums);

            for(int i=0;i<nums.length-2;i++){
                int tempMax=nums[i]*nums[i+1]*nums[i+2];
                max=Math.max(max,tempMax);
            }
            int n=nums.length;
            int  sum=  Math.max(nums[0]*nums[1]*nums[n-1],nums[n-1]*nums[n-2]*nums[n-3]);
            max=Math.max(max,sum);

            return max;
    }
}

二分查找

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

示例 1:

输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4

示例 2:
输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1

class Solution {
    public int search(int[] nums, int target) {
            int left=0;
            int right=nums.length-1;
            int mid=0;
            while(left<=right){
                mid=left+(right-left)/2;
                if(nums[mid]==target){
                    return mid;
                }else if(nums[mid]>target){
                        right=mid-1;    
                }else {
                    left=mid+1;
                }
            }
            return -1;
    }
}

二维数组中的查找

在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数

示例:

现有矩阵 matrix 如下:

[
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
]
给定 target = 5,返回 true。

给定 target = 20,返回 false。

class Solution {
    public boolean findNumberIn2DArray(int[][] matrix, int target) {
        //判空操作
            if(matrix==null){
                return false;
            }
            if(matrix.length==0){
                return false;
            }
            //right top 是右上角 为什么选右上角 因为右上角 往左边永远是减往下面永远是加
                int right=matrix[0].length-1;
                int top=0;
                //当top不大于最低 right 不小于0 那么找到就是true 找不到判断大小继续找大了就往左边挪  小了往下边加
                while(right>=0&&top<matrix.length){
                    if(matrix[top][right]==target){
                        return true;
                    }else if(matrix[top][right]>target){
                        right--;
                    }else if(matrix[top][right]<target){
                        top++;
                    }
                }

                return false;
    }
}

剑指 Offer 07. 重建二叉树

输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。

假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

 

示例 1:

Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
Output: [3,9,20,null,null,15,7]
示例 2:

Input: preorder = [-1], inorder = [-1]
Output: [-1]


/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        int n=preorder.length;
        //判空
        if(n==0){
            return null;
        }
        //先找出 这个前序根在中序的那个位置
        int rootValue=preorder[0];
        int rootIndex=0;
        TreeNode rootTree = new TreeNode(rootValue);
        for(int i=0;i<n;i++){
            if(inorder[i]==rootValue){
                rootIndex=i;
            }
        } 
        //左子树就是前序
        rootTree.left=buildTree(Arrays.copyOfRange(preorder,1,1+rootIndex),Arrays.copyOfRange(inorder,0,0+rootIndex));
        rootTree.right=buildTree(Arrays.copyOfRange(preorder,1+rootIndex,n)
        ,Arrays.copyOfRange(inorder,rootIndex+1,n));


        return rootTree;
    }
}

旋转数组的最小数字

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。

给你一个可能存在 重复 元素值的数组 numbers ,它原来是一个升序排列的数组,并按上述情形进行了一次旋转。请返回旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一次旋转,该数组的最小值为1。  

示例 1:

输入:[3,4,5,1,2]
输出:1
示例 2:

输入:[2,2,2,0,1]
输出:0

class Solution {
    public int minArray(int[] numbers) {
        Arrays.sort(numbers);

        return numbers[0];

    }
}

调整数组顺序使奇数位于偶数前面

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数在数组的前半部分,所有偶数在数组的后半部分。

 

示例:

输入:nums = [1,2,3,4]
输出:[1,3,2,4]
注:[3,1,2,4] 也是正确的答案之一。


class Solution {
    public int[] exchange(int[] nums) {
        ArrayList firstList=new ArrayList<Integer>();
        ArrayList secondList=new ArrayList<Integer>();

        for(int i=0;i<nums.length;i++){
            if(nums[i]%2==0){
                secondList.add(nums[i]);
            }else{
                firstList.add(nums[i]);
            }
        }

        for(int i=0;i<firstList.size();i++){
            System.out.print(firstList.get(i));
            nums[i]=(int)firstList.get(i);
        }

        for(int i=0;i<secondList.size();i++){
                System.out.print(secondList.get(i));
               nums[firstList.size()+i]=(int)secondList.get(i); 
        }
        return nums;
    }
}

顺时针打印矩阵

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。

 

示例 1:

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
示例 2:

输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]  

class Solution {
    public int[] spiralOrder(int[][] matrix) {
            //如果为空或者集合就一个 那么返回一个
            if(matrix==null||matrix.length==0||matrix[0].length==0){
                int [] arr=new int[0];
                return  arr;
            }

            //左边
            int left=0;
            //右边
            int right=matrix[0].length-1;
            //上边
            int top=0;
            //下边
            int botton=matrix.length-1;
            //存储集合的边界
            ArrayList<Integer> list=new ArrayList<Integer>();
        //如果左边小于右边 或者下边大于上边
           while(left<=right&&botton>=top){
            //先从左到右加入
            for(int i=left;i<=right;i++){
                list.add(matrix[top][i]);
            }
            //从上到下加入
            for(int i=top+1;i<=botton;i++){
                list.add(matrix[i][right]);
            }
            //从右到左加入  但是要求上下不能相等 不然会给上面重复计算
            for(int i=right-1;i>=left&&botton!=top;i--){
                list.add(matrix[botton][i]);
            }
            //从下到上,但是要求左和右不能相等
            for(int i=botton-1;i>=top+1&&left!=right;i--){
                list.add(matrix[i][left]);
            }
            top++;
            right--;
            botton--;
            left++;
            }
            int [] arr=new int[list.size()];

            for(int i=0;i<list.size();i++){
                arr[i]=list.get(i);
            }
            return arr;
    }
}

数组中出现次数超过一半的数字

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。

 

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

 

示例 1:

输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
输出: 2  

class Solution {
    public int majorityElement(int[] nums) {
            HashMap map=new HashMap<Integer,Integer>();
            for(int i=0;i<nums.length;i++){
                    if(map.get(nums[i])!=null){
                         map.put(nums[i],(int)map.get(nums[i])+1);   
                    }else{
                        map.put(nums[i],1);
                    }
            }
            Set<Integer> sets =map.keySet();
            for(Integer value : sets ){
                System.out.println("key"+value);
                System.out.println("value"+map.get(value));

                if((int)map.get(value)>nums.length/2){
                    return value;
                }

            }

            return -1;
    }
}

最小的k个数

输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。

 

示例 1:

输入:arr = [3,2,1], k = 2
输出:[1,2] 或者 [2,1]
示例 2:

输入:arr = [0,1,2,1], k = 1
输出:[0]

class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {

        Arrays.sort(arr);
        int[] result=new int[k];
        for(int i=0;i<k;i++){
            result[i]=arr[i];
        }
        return result;
    }
}

连续子数组的最大和

输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。

要求时间复杂度为O(n)。

 

示例1:

输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

class Solution {
    public int maxSubArray(int[] nums) {
            if(nums.length==1){
                return nums[0];
            }

        //这个是最后的值大小
        int max=nums[0];
        //这个是临时的一个最大值 因为是连续的一个最大值 所以需要这个临时的,
        int tempMax=nums[0];

        for(int i=1;i<nums.length;i++){
            //这个最大值就是之前积累的加上这个值大 还是单个这个大
            tempMax=Math.max(nums[i],tempMax+nums[i]);
            //把连续加上的判断的值和之前积累的最大值做 最大留存就得出了
            max=Math.max(max,tempMax); 
        }


        return max;

    }
}

在排序数组中查找数字 I

统计一个数字在排序数组中出现的次数。

示例 1:

输入: nums = [5,7,7,8,8,10], target = 8
输出: 2
示例 2:

输入: nums = [5,7,7,8,8,10], target = 6
输出: 0

class Solution {
    public int search(int[] nums, int target) {
           HashMap map= new HashMap<Integer,Integer>();

        for(int i=0;i<nums.length;i++){
            if(map.get(nums[i])==null){
                 map.put(nums[i],1);
            }else{
                int temp=(int)map.get(nums[i]);
                map.put(nums[i],temp+1);
            }
      }

         if(map.get(target)==null){
             return 0;
         }else{
            return (int)map.get(target);
         }


    }
}

0~n-1中缺失的数字

一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。

 

示例 1:

输入: [0,1,3]
输出: 2
示例 2:

输入: [0,1,2,3,4,5,6,7,9]
输出: 8


class Solution {
    public int missingNumber(int[] nums) {

       
            for(int i=0;i<nums.length;i++){
                if(nums[i]!=i){
                    return i;
                }
            }

            return nums[nums.length-1]+1;
    }
}

扑克牌中的顺子

从若干副扑克牌中随机抽 5 张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王为 0 ,可以看成任意数字。A 不能视为 14。

 

示例 1:

输入: [1,2,3,4,5]
输出: True  

示例 2:

输入: [0,0,1,2,5]
输出: True

class Solution {
    public boolean isStraight(int[] nums) {
            //先排序一下
            Arrays.sort(nums);
            //搞
            int zoreNumber=0;

            for(int i=0;i<nums.length-1;i++){
                if(nums[i]==0){
                    zoreNumber++;
                    continue;
                }

                if(nums[i+1]==nums[i]){
                    return false;
                }

                zoreNumber=zoreNumber-(nums[i+1]-nums[i]-1);
            }
            System.out.print("zoreNumber"+zoreNumber);
            if(zoreNumber>=0){
                return true;
            }else{
                return false;
            }
    }
}

股票的最大利润

假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少?

 

示例 1:

输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
示例 2:

输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。


class Solution {
    public int maxProfit(int[] prices) {

        int minValue=Integer.MAX_VALUE;
        int maxResult=0;
        for(int i=0;i<prices.length;i++){
            minValue =Math.min(minValue,prices[i]);
            int tempResult =prices[i]-minValue;

            maxResult=Math.max(maxResult,tempResult);
        }
        return maxResult;
    }
}

数组中和为 0 的三个数

给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a ,b ,c ,使得 a + b + c = 0 ?请找出所有和为 0 且 不重复 的三元组。

 

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
示例 2:

输入:nums = []
输出:[]
示例 3:

输入:nums = [0]
输出:[]

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
            Arrays.sort(nums);
          ArrayList<List<Integer>> result=  new ArrayList<List<Integer>>();
          ArrayList<Integer> arrList= new ArrayList<Integer>();
         
            for(int i=0;i<nums.length;i++){
                int target=-nums[i];
                int start=i+1;
                int end=nums.length-1;

                while(start<end&&start<=nums.length-1&&end<=nums.length-1){
                    if(nums[start]+nums[end]==target){
                        ArrayList<Integer> list=new ArrayList();
                        list.add(nums[start]);
                        list.add(nums[end]);
                        list.add(nums[i]);
                        if(!result.contains(list)){
                            result.add(list);
                        }
                        start++;
                        end--;
                    }else if(nums[start]+nums[end]<target){
                        start++;
                    }else{
                        end--;
                    }
                }
            }
        return result;
    }
}

合并排序的数组

给定两个排序后的数组 A 和 B,其中 A 的末端有足够的缓冲空间容纳 B。 编写一个方法,将 B 合并入 A 并排序。

初始化 A 和 B 的元素数量分别为 m 和 n。

示例:

输入:
A = [1,2,3,0,0,0], m = 3
B = [2,5,6], n = 3

输出: [1,2,2,3,5,6]

class Solution {
    public void merge(int[] A, int m, int[] B, int n) {

       

        for(int i=m;i<m+n;i++){
            A[i]=B[i-m];
        }

        Arrays.sort(A);

    }
}

搜索旋转数组

搜索旋转数组。给定一个排序后的数组,包含n个整数,但这个数组已被旋转过很多次了,次数不详。请编写代码找出数组中的某个元素,假设数组元素原先是按升序排列的。若有多个相同元素,返回索引值最小的一个。

示例1:

输入: arr = [15, 16, 19, 20, 25, 1, 3, 4, 5, 7, 10, 14], target = 5
输出: 8(元素5在该数组中的索引)
示例2:

输入:arr = [15, 16, 19, 20, 25, 1, 3, 4, 5, 7, 10, 14], target = 11
输出:-1 (没有找到)

class Solution {
    public int search(int[] arr, int target) {

        for(int i=0;i<arr.length;i++){
                if(arr[i]==target){
                    return i;
                }
        } 
        return -1;
    }
}

排序矩阵查找

给定M×N矩阵,每一行、每一列都按升序排列,请编写代码找出某元素。

示例:

现有矩阵 matrix 如下:

[
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
]
给定 target = 5,返回 true。

给定 target = 20,返回 false。


class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        if(matrix==null||matrix.length==0){
            return false;
        }

        //  遍历的做法
        //   int colume=-1;
        //   int m=matrix.length;
        //   int n=matrix[0].length;
        //  for(int i=0;i<m;i++){
        //      for(int j=0;j<n;j++){
        //          if(matrix[i][j]==target){
        //              return true;
        //          }
                 
        //      }
        //  }

            int m=0;
            int n=matrix[0].length-1;
            while(m<matrix.length&&n>=0){
                if(matrix[m][n]==target){
                    return true;
                }else if(matrix[m][n]>target){
                    n--;
                }else{
                    m++;
                }
            }
         return false;
    }
}

连续数列

给定一个整数数组,找出总和最大的连续数列,并返回总和。

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
进阶:

如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。

class Solution {
    public int maxSubArray(int[] nums) {
        if(nums==null||nums.length==0){

            return -1;
        }

        int max=nums[0];
        int current=nums[0];
        for(int i=1;i<nums.length;i++){

            if(current+nums[i]>nums[i]){
                current=current+nums[i];
            }else{
                current=nums[i];
            }
            max=Math.max(current,max);
        }
            return max;
    }
}

字符串

无重复字符的最长子串

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:

输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:

输入: s = “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:

输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
  请注意,你的答案必须是 子串 的长度,”pwke” 是一个子序列,不是子串。
示例 4:

输入: s = “”
输出: 0

class Solution {
    public int lengthOfLongestSubstring(String s) {
            char chars[]= s.toCharArray();
            int max=0;
            ArrayList<Character> list= new  ArrayList();

            if(s==null||s.length()==0){
                return 0;
            }

            for(int i=0;i<chars.length;i++){
                  Character character=  new Character(chars[i]);
                    if(list.contains(character)){
                        int index=list.indexOf(character);

                        for(int j=index;j>=0;j--){
                            list.remove(j);
                        }
                        if(!list.contains(character)){
                            list.add(character);
                        }
                    }else{
                        list.add(character);
                        max=Math.max(max,list.size());
                    }
            }
            return max;
    }
}

最长回文子串

给你一个字符串 s,找到 s 中最长的回文子串。

 

示例 1:

输入:s = “babad”
输出:”bab”
解释:”aba” 同样是符合题意的答案。
示例 2:

输入:s = “cbbd”
输出:”bb”
示例 3:

输入:s = “a”
输出:”a”
示例 4:

输入:s = “ac”
输出:”a”

class Solution {
    public String longestPalindrome(String s) {

        char chars[]=s.toCharArray();
        int length=s.length();
        if(length<2){
            return s;
        }
        Boolean arr[][]=new Boolean[length][length];

        for(int i=0;i<length;i++){
            arr[i][i]=true;
        }

        int maxhublength=1;
        int start=0;


        for(int j=1;j<length;j++){
            for(int i=0;i<j;i++){
                if(chars[j]!=chars[i]){
                        arr[i][j]=false;
                }else{
                    if(j-i<3){
                        arr[i][j]=true;
                    }else{
                         arr[i][j]=arr[i+1][j-1];
                    }
                }
                if(((j-i+1)>maxhublength)&&arr[i][j]){
                    maxhublength=j-i+1;
                    start=i;
                }
            }
        }

      //不会

        String result=s.substring(start,start+maxhublength);        

        return  result;
    }
}

最长公共前缀

编写一个函数来查找字符串数组中的最长公共前缀。

如果不存在公共前缀,返回空字符串 “”。

 

示例 1:

输入:strs = [“flower”,”flow”,”flight”]
输出:”fl”
示例 2:

输入:strs = [“dog”,”racecar”,”car”]
输出:””
解释:输入不存在公共前缀。


class Solution {
    public String longestCommonPrefix(String[] strs) {
        //先判空一下
        if(strs==null||strs.length==0){
            return "";
        }
        // 拿第一个为基准
        String firstString=strs[0];
        //这个是一个字符串的建造器
        StringBuilder build= new StringBuilder();
        //遍历第一个字符串的字符
        for(int i=0;i<firstString.length();i++){
            char c=firstString.charAt(i);
            //如果某一个字符串的字符没有对应字符就会被return  因为是要连续一样的字符串
            for(int j=1;j<strs.length;j++){
                if(strs[j].length()<=i||c!=strs[j].charAt(i)){
                   return build.toString();
                }
            }
            build.append(c);
        }
        return build.toString();
    }
}

有效的括号

给定一个只包括 ‘(‘,’)’,’{‘,’}’,’[‘,’]’ 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。  

示例 1:

输入:s = “()”
输出:true
示例 2:

输入:s = “()[]{}”
输出:true
示例 3:

输入:s = “(]”
输出:false
示例 4:

输入:s = “([)]”
输出:false
示例 5:

输入:s = “{[]}”
输出:true


class Solution {
    public boolean isValid(String s) {
    //搞一个栈
      Stack<Character> stack=  new Stack<>();
    //遍历这个字符串
      for(int i=0;i<s.length();i++){
          //因为只有三种类型,看到某一个就放入相反的即可
          char c=s.charAt(i);
          if(c=='('){
              stack.push(')');
          }else if(c=='{'){
              stack.push('}');
          }else if(c=='['){
              stack.push(']');
              //如果遍历还没有为空  或者弹出来的字符跟放进去的不一样 那么就返回false
          }else if (stack.isEmpty()||c!=stack.pop()){
              return false;
          }
      }
      return stack.isEmpty();
    }
}

 

括号生成

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

示例 1:

输入:n = 3
输出:[“((()))”,”(()())”,”(())()”,”()(())”,”()()()”]
示例 2:

输入:n = 1
输出:[“()”]

class Solution {
    public List<String> generateParenthesis(int n) {
     List<String> res=new ArrayList<String>();
        generate(res,"",0,0,n);
        return res;
    }

    public void generate(List<String> res,String ans,int count1,int count2,int n){
             if(count1>n||count2>n){
                return;
            }

            if(count2==n&&count1==n){
                res.add(ans);
            }

             if(count1>=count2){
               String ans1 = new String(ans);
             generate(res, ans+"(", count1+1, count2, n);
                 generate(res, ans1+")", count1, count2+1, n);
            }
        //不是很懂

    }
}

字符串相乘

给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。

注意:不能使用任何内置的 BigInteger 库或直接将输入转换为整数。

 

示例 1:

输入: num1 = “2”, num2 = “3”
输出: “6”
示例 2:

输入: num1 = “123”, num2 = “456”
输出: “56088”  

class Solution {
    public String multiply(String num1, String num2) {
        if (num1.equals("0") || num2.equals("0")) {
            return "0";
        }
        String ans = "0";
        int m = num1.length(), n = num2.length();
        for (int i = n - 1; i >= 0; i--) {
            StringBuffer curr = new StringBuffer();
            int add = 0;
            for (int j = n - 1; j > i; j--) {
                curr.append(0);
            }
            int y = num2.charAt(i) - '0';
            for (int j = m - 1; j >= 0; j--) {
                int x = num1.charAt(j) - '0';
                int product = x * y + add;
                curr.append(product % 10);
                add = product / 10;
            }
            if (add != 0) {
                curr.append(add % 10);
            }
            ans = addStrings(ans, curr.reverse().toString());
        }
        return ans;
    }

    public String addStrings(String num1, String num2) {
        int i = num1.length() - 1, j = num2.length() - 1, add = 0;
        StringBuffer ans = new StringBuffer();
        while (i >= 0 || j >= 0 || add != 0) {
            int x = i >= 0 ? num1.charAt(i) - '0' : 0;
            int y = j >= 0 ? num2.charAt(j) - '0' : 0;
            int result = x + y + add;
            ans.append(result % 10);
            add = result / 10;
            i--;
            j--;
        }
        ans.reverse();
        return ans.toString();
        //这个题不会 想不明白
    }
}

复原 IP 地址

有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 ‘.’ 分隔。

例如:”0.1.2.201” 和 “192.168.1.1” 是 有效 IP 地址,但是 “0.011.255.245”、”192.168.1.312” 和 “192.168@1.1“ 是 无效 IP 地址。
给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s 中插入 ‘.’ 来形成。你不能重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。

 

示例 1:

输入:s = “25525511135”
输出:[“255.255.11.135”,”255.255.111.35”]
示例 2:

输入:s = “0000”
输出:[“0.0.0.0”]
示例 3:

输入:s = “1111”
输出:[“1.1.1.1”]
示例 4:

输入:s = “010010”
输出:[“0.10.0.10”,”0.100.1.0”]
示例 5:

输入:s = “101023”
输出:[“1.0.10.23”,”1.0.102.3”,”10.1.0.23”,”10.10.2.3”,”101.0.2.3”]

class Solution {
    public List<String> restoreIpAddresses(String s) {
  ArrayList<String> strings = new ArrayList<>();

        for (int i = 1; i < 4; i++) {
            for (int j = 1; j < 4; j++) {
                for (int k = 1; k < 4; k++) {
                    for (int l = 0; l < 4; l++) {
                        if (i + j + k + l == s.length()) {
                            String s1 = s.substring(0, i);
                            String s2 = s.substring(i, i+j);
                            String s3 = s.substring(i + j, i + j + k);
                            String s4 = s.substring(i + j + k, i + j + k + l);
                            if (checkout(s1) && checkout(s2) && checkout(s3) && checkout(s4)) {
                                StringBuilder builder = new StringBuilder();
                                String ip = builder.append(s1).append(".").append(s2).append(".").append(s3).append(".").append(s4).toString();
                                strings.add(ip);
                            }
                        }
                    }
                }
            }

        }
        return strings;
    }
    
    
      public boolean checkout(String s) {
        if (s.equals("")){
            return false;
        }

        if (s.charAt(0) == '0' && s.length() != 1) {
            return false;
        } else if (s.charAt(0) == '0' && s.length() == 1) {
            return true;
        }

        try {
            if (Integer.valueOf(s) <= 255) {
                if (s.charAt(0) != '0') {
                    return true;
                } else {
                    return false;
                }
            }
        } catch (Exception e) {
            return false;
        }
        return false;
    }
    //这个题也是不太会的
    
}

 

验证回文串

class Solution {
    public boolean isPalindrome(String s) {
            if(s==null||s.length()==0){
                return false;
            }
            //先把它搞成小写的字母
            s=s.toLowerCase();
            //搞一个列表存储
            ArrayList<Character> list=new ArrayList<Character>();
            //遍历 判断是否是空和字母 数字 只加字母和数字
            for(int i=0;i<s.length();i++){
                char c=s.charAt(i);
                if(c!=' '&&c-'a'<26&&c-'a'>=0){
                    list.add(c);
                }
                if(c>='0'&&c<='9'){
                    list.add(c);
                }
            }
            //判断头尾是否相等就可以了
        for(int i=0;i<(list.size()/2);i++){
            if(list.get(i)!=list.get(list.size()-i-1)){
                return false;
            }
        }

            return  true;
    }
}

比较版本号

给你两个版本号 version1 和 version2 ,请你比较它们。

版本号由一个或多个修订号组成,各修订号由一个 ‘.’ 连接。每个修订号由 多位数字 组成,可能包含 前导零 。每个版本号至少包含一个字符。修订号从左到右编号,下标从 0 开始,最左边的修订号下标为 0 ,下一个修订号下标为 1 ,以此类推。例如,2.5.33 和 0.1 都是有效的版本号。

比较版本号时,请按从左到右的顺序依次比较它们的修订号。比较修订号时,只需比较 忽略任何前导零后的整数值 。也就是说,修订号 1 和修订号 001 相等 。如果版本号没有指定某个下标处的修订号,则该修订号视为 0 。例如,版本 1.0 小于版本 1.1 ,因为它们下标为 0 的修订号相同,而下标为 1 的修订号分别为 0 和 1 ,0 < 1 。

返回规则如下:

如果 version1 > version2 返回 1,
如果 version1 < version2 返回 -1,
除此之外返回 0。  

示例 1:

输入:version1 = “1.01”, version2 = “1.001”
输出:0
解释:忽略前导零,”01” 和 “001” 都表示相同的整数 “1”
示例 2:

输入:version1 = “1.0”, version2 = “1.0.0”
输出:0
解释:version1 没有指定下标为 2 的修订号,即视为 “0”
示例 3:

输入:version1 = “0.1”, version2 = “1.1”
输出:-1
解释:version1 中下标为 0 的修订号是 “0”,version2 中下标为 0 的修订号是 “1” 。0 < 1,所以 version1 < version2

class Solution {
    public int compareVersion(String version1, String version2) {
        //先根据. 切割字符
          String [] a1 =  version1.split("\\.");
          String [] a2 =  version2.split("\\.");
        //例子1 需要把前面的0给删除但是 Integer.valueOf 已经能满足这一点
        //例子2 需要缺少下标的时候把值默认为0
        //这个题就是题目太难理解了
          for(int n=0;n<Math.max(a1.length,a2.length);n++){
              int i=(n<a1.length?Integer.valueOf(a1[n]):0);
              int j=(n<a2.length?Integer.valueOf(a2[n]):0);
              if(i<j){
                  return -1;
              }else if(i>j){
                   return 1;
              }
          }
          return 0;
    }
}

最大数

给定一组非负整数 nums,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。

注意:输出结果可能非常大,所以你需要返回一个字符串而不是整数。

 

示例 1:

输入:nums = [10,2]
输出:”210”
示例 2:

输入:nums = [3,30,34,5,9]
输出:”9534330”
示例 3:

输入:nums = [1]
输出:”1”
示例 4:

输入:nums = [10]
输出:”10”

class Solution {
    public String largestNumber(int[] nums) {
            //进行冒泡排序 排序的核心是 将两个字符加起来,然后进行排序大的排前面 小的排后面
            for(int i=0;i<nums.length;i++){
                for(int j=i+1;i<nums.length;j++){
                    if(i>=nums.length||j>=nums.length){
                        break;
                    }
                    String temp1=nums[i]+""+nums[j];
                    String temp2=nums[j]+""+nums[i];
                    if(Long.parseLong(temp1)<Long.parseLong(temp2)){
                            int temp=nums[i];
                             nums[i]=nums[j];
                             nums[j]=temp;
                    }
                }
            }

            //排完序的数组进行拼接 最后完成
          StringBuilder build= new StringBuilder();
            for(int i=0;i<nums.length;i++){
                if("0".equals(build.toString())&&nums[i]==0){
                        continue;
                }
               build.append(nums[i]);
            }

            return build.toString();
    }
}

反转字符串

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。

不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

 

示例 1:

输入:s = [“h”,”e”,”l”,”l”,”o”]
输出:[“o”,”l”,”l”,”e”,”h”]
示例 2:

输入:s = [“H”,”a”,”n”,”n”,”a”,”h”]
输出:[“h”,”a”,”n”,”n”,”a”,”H”]

class Solution {
    public void reverseString(char[] s) {

        // 遍历列表 将最后一个和第一个取出来 然后进行调换就可以了
        for(int i=0;i<s.length/2;i++){
            char first=s[i];
            char last=s[s.length-1-i];
            char temp =first;
            first=last;
            last=temp;
            s[i]=first;
            s[s.length-1-i]=last;
        }



    }
}

字符串相加

给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和并同样以字符串形式返回。

你不能使用任何內建的用于处理大整数的库(比如 BigInteger), 也不能直接将输入的字符串转换为整数形式。

 

示例 1:

输入:num1 = “11”, num2 = “123”
输出:”134”
示例 2:

输入:num1 = “456”, num2 = “77”
输出:”533”
示例 3:

输入:num1 = “0”, num2 = “0”
输出:”0”


class Solution {
    public String addStrings(String num1, String num2) {
        //将字符串长度
        int l1=num1.length()-1;
        int l2=num2.length()-1;
        //标志是否进位了
        int add=0;
        //字符串建造者
        StringBuilder build=new StringBuilder();
        //
        while(add!=0||l1>=0||l2>=0){
            //获取最低位然后减去’0‘拿到数值 如果长度低于0了 那么就返回0
             int x=l1>=0?num1.charAt(l1)-'0':0;   
             int y=l2>=0?num2.charAt(l2)-'0':0;
             System.out.print("x"+x);      
             System.out.print("y"+y);      
            //两个数相加 然后加上进位的那个数
             int sum=x+y+add;
            //这个数取模
             int result=sum%10; 
             //除以10 看是否有进位
            add=sum/10; 
            //将这个进位放到字符串数组中,但是这个是一个反序的
            build.append(result);
            //当然要长度同时减1
            --l1;
            --l2;
        }
        //将字符串反转
        return build.reverse().toString();
      

    }
}

验证IP地址

编写一个函数来验证输入的字符串是否是有效的 IPv4 或 IPv6 地址。

如果是有效的 IPv4 地址,返回 “IPv4” ;
如果是有效的 IPv6 地址,返回 “IPv6” ;
如果不是上述类型的 IP 地址,返回 “Neither” 。
IPv4 地址由十进制数和点来表示,每个地址包含 4 个十进制数,其范围为 0 - 255, 用(“.”)分割。比如,172.16.254.1;

同时,IPv4 地址内的数不会以 0 开头。比如,地址 172.16.254.01 是不合法的。

IPv6 地址由 8 组 16 进制的数字来表示,每组表示 16 比特。这些组数字通过 (“:”)分割。比如,  2001:0db8:85a3:0000:0000:8a2e:0370:7334 是一个有效的地址。而且,我们可以加入一些以 0 开头的数字,字母可以使用大写,也可以是小写。所以, 2001:db8:85a3:0:0:8A2E:0370:7334 也是一个有效的 IPv6 address地址 (即,忽略 0 开头,忽略大小写)。

然而,我们不能因为某个组的值为 0,而使用一个空的组,以至于出现 (::) 的情况。 比如, 2001:0db8:85a3::8A2E:0370:7334 是无效的 IPv6 地址。

同时,在 IPv6 地址中,多余的 0 也是不被允许的。比如, 02001:0db8:85a3:0000:0000:8a2e:0370:7334 是无效的。

 

示例 1:

输入:IP = “172.16.254.1”
输出:”IPv4”
解释:有效的 IPv4 地址,返回 “IPv4”
示例 2:

输入:IP = “2001:0db8:85a3:0:0:8A2E:0370:7334”
输出:”IPv6”
解释:有效的 IPv6 地址,返回 “IPv6”
示例 3:

输入:IP = “256.256.256.256”
输出:”Neither”
解释:既不是 IPv4 地址,又不是 IPv6 地址
示例 4:

输入:IP = “2001:0db8:85a3:0:0:8A2E:0370:7334:”
输出:”Neither”
示例 5:

输入:IP = “1e1.4.5.6”
输出:”Neither”

class Solution {
    public String validIPAddress(String ip) {
        //先将ip进行切割
            String[] ipv4=ip.split("\\.");
            String[] ipv6=ip.split(":");
        //按正常的规则
            if(ipv4.length==4&&ip.charAt(0)!='.'&&ip.charAt(ip.length()-1)!='.'){
                //遍历ip
                for(String s : ipv4){
                    if(s.length()==0||s.length()>=4||(s.charAt(0)=='0'&&s.length()>1)){
                        return "Neither";
                    }
                    int num=0;
                    //遍历数组下面的规则 每个小数组 只能是数字 且数字相加不能超过256
                    for(int i=0;i<s.length();i++){
                        char ch=s.charAt(i);
                        if(ch<'0'||ch>'9'){
                            return "Neither";
                        }else{
                            num=num*10+(ch-'0');
                        }
                        System.out.print("num"+num);
                        if(num>=256){
                            return "Neither";
                        }
                    }

                }
                return "IPv4";
            }

        //ipv6 数组长度不能超过8  全部能不能超过16 不能 :开头或者结尾
  if (ipv6.length == 8 && ip.length() >= 15 && ip.charAt(0) != ':' 
        && ip.charAt(ip.length() - 1) != ':') {
            for (String s : ipv6) {
                if (s.length() == 0 || s.length() > 4) return "Neither";
                for (int i = 0; i < s.length(); i++) {
                    char ch = s.charAt(i);
                    System.out.print(ch);
                    if (!(ch >= '0'  && ch <= '9' || ch >= 'A' && ch <= 'F' 
                    || ch >= 'a' && ch <= 'f')) return "Neither";
                }
            }
            return "IPv6";
        }
        return "Neither";
    }
}

最长回文子序列

给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。

子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。

 

示例 1:

输入:s = “bbbab”
输出:4
解释:一个可能的最长回文子序列为 “bbbb” 。
示例 2:

输入:s = “cbbd”
输出:2
解释:一个可能的最长回文子序列为 “bb” 。  

 class Solution {
    public int longestPalindromeSubseq(String s) {
            int n=s.length();
            int [][] dp=new int[n][n];

            for(int i=n-1;i>=0;i--){
                dp[i][i]=1;
                char c1=s.charAt(i);
                for(int j=i+1;j<n;j++){
                    char c2=s.charAt(j);
                    if(c1==c2){
                        dp[i][j]=dp[i+1][j-1]+2;
                    }else{
                        dp[i][j]=Math.max(dp[i+1][j],dp[i][j-1]);
                    }
                }
            }
            //不太会
        return dp[0][n-1];
    }
}
 
 

最长公共子序列

给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。

一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。

例如,”ace” 是 “abcde” 的子序列,但 “aec” 不是 “abcde” 的子序列。
两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。

 

示例 1:

输入:text1 = “abcde”, text2 = “ace”
输出:3
解释:最长公共子序列是 “ace” ,它的长度为 3 。
示例 2:

输入:text1 = “abc”, text2 = “abc”
输出:3
解释:最长公共子序列是 “abc” ,它的长度为 3 。
示例 3:

输入:text1 = “abc”, text2 = “def”
输出:0
解释:两个字符串没有公共子序列,返回 0 。


class Solution {
    public int longestCommonSubsequence(String text1, String text2) {
            int m=text1.length();
            int n=text2.length();

// 为了把第一行和第一列给空出来
            int[][] arr=new int [m+1][n+1];

      // 从1行开始 第一列开始
            for(int i=1;i<=m;i++){
                for(int j=1;j<=n;j++){
                    //如果相等那么就是大家的上一个加1也就是左上角
                    char c1= text1.charAt(i-1);
                    char c2=text2.charAt(j-1);
                    if(c1==c2){
                        arr[i][j]=arr[i-1][j-1]+1;
                    }else{
                        //如果不相等,那么就取上面和左边的最大值,也就是两个长度的数组的最大值
                        arr[i][j]=Math.max(arr[i-1][j],arr[i][j-1]);
                    }

                }
            }
                return arr[m][n];
    }
}

字符串的排列

输入一个字符串,打印出该字符串中字符的所有排列。

 

你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。

 

示例:

输入:s = “abc”
输出:[“abc”,”acb”,”bac”,”bca”,”cab”,”cba”]  

class Solution {
    public String[] permutation(String s) {
     Set<String> list=new HashSet<>();
        char[]arr=s.toCharArray();
        StringBuilder sb =new StringBuilder();
        boolean[] visited=new boolean[arr.length];
        dfs(arr,"",visited,list);
        return list.toArray(new String[0]);
    }

    public void dfs(char[] arr,String s,boolean[] visited,Set<String> list){
            if(s.length()==arr.length){
                list.add(s);
                return;
            }

            for(int i=0;i<arr.length;i++){
                if(visited[i]){
                    continue;
                }
                visited[i]=true;
                dfs(arr,s+String.valueOf(arr[i]),visited,list);
                visited[i]=false;
            }
        //不太会

    }
    
}

给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。

 

示例 1:

输入: 12258
输出: 5
解释: 12258有5种不同的翻译,分别是”bccfi”, “bwfi”, “bczi”, “mcfi”和”mzi”  

class Solution {
    public int translateNum(int num) {
        //因为问的是个数
        //如果小于9 那么就只有一种可能
            if(num<=9){
                return 1;
            }
            //先拿最后两位出来
            int ba=num%100;
            if(ba>=26||ba<=9){
                //如果小于9且大于26 那么切割一次
               return translateNum(num/10);      
            }else{
                //如果在26和9之间的那么有两种可能 一种是切一次 种是切两次
                return translateNum(num/10)+translateNum(num/100);
            }
       

    }
}

第一个只出现一次的字符

在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。

示例 1:

输入:s = “abaccdeff”
输出:’b’
示例 2:

输入:s = “”
输出:’ ‘

class Solution {
    public char firstUniqChar(String s) {
        char result=' ';
        //存储字符和对应的次数
      HashMap<Character,Integer> map= new HashMap<Character,Integer>();
      //将字符串和次数整理到map中
        for(int i=0;i<s.length();i++){
           char at= s.charAt(i);
            if(map.get(at)==null){
                map.put(at,1);
            }else{
               int value= (int)map.get(at);
               map.put(at,value+1);
            }
        }
        //遍历map找出次数为1的
       Set<Character> sets= map.keySet();

      ArrayList<Character> list=  new ArrayList<Character>();

       for(Character c:sets){
           if((int)map.get(c)==1){
              list.add(c);
           }
       }
       //通过字符串遍历 如果存在次数为1的返回,可以完成第一次的设定
       for(int i=0;i<s.length();i++){
            if(list.contains(s.charAt(i))){
                return s.charAt(i);
            }
       }
        return result;
    }

 
}



翻转单词顺序

输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串”I am a student. “,则输出”student. a am I”。

 

示例 1:

输入: “the sky is blue”
输出: “blue is sky the”
示例 2:

输入: “  hello world!  “
输出: “world! hello”
解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
示例 3:

输入: “a good   example”
输出: “example good a”
解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。

class Solution {
    public String reverseWords(String s) {
        if(s==null||s.length()==0){
            return "";
        }
        //先把字符串的前面和后面空格去掉
        s=s.trim();
        String result="";
        //将字符串按空格切割
        String [] strArr=s.split(" ");
        //将数组的前面和后面进行调转
        for(int i=0;i<strArr.length/2;i++){
            String firstStr=strArr[i];
            String secondStr=strArr[strArr.length-1-i];
            String tempStr=firstStr;
             firstStr=secondStr;
             secondStr=tempStr;
            strArr[i]=firstStr;
            strArr[strArr.length-1-i]=secondStr;
        }
        //最后拼接回来
        for(int i=0;i<strArr.length;i++){
            result=result.trim()+" "+strArr[i];
        }


        return result.trim();

    }
}

把字符串转换成整数

写一个函数 StrToInt,实现把字符串转换成整数这个功能。不能使用 atoi 或者其他类似的库函数。

 

首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。

当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。

该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。

注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。

在任何情况下,若函数不能进行有效的转换时,请返回 0。

说明:

假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231,  231 − 1]。如果数值超过这个范围,请返回  INT_MAX (231 − 1) 或 INT_MIN (−231) 。

示例 1:

输入: “42”
输出: 42
示例 2:

输入: “ -42”
输出: -42
解释: 第一个非空白字符为 ‘-‘, 它是一个负号。
  我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。
示例 3:

输入: “4193 with words”
输出: 4193
解释: 转换截止于数字 ‘3’ ,因为它的下一个字符不为数字。
示例 4:

输入: “words and 987”
输出: 0
解释: 第一个非空字符是 ‘w’, 但它不是数字或正、负号。
因此无法执行有效的转换。
示例 5:

输入: “-91283472332”
输出: -2147483648
解释: 数字 “-91283472332” 超过 32 位有符号整数范围。
  因此返回 INT_MIN (−231) 。

class Solution {
    public int strToInt(String str) {
            //字符串先去空格
            str=str.trim();
            int result=0;
            //标志是否应该取反
            boolean reverse=false;
            //字符串为空 或者长度为0
            if(str==null||str.length()==0){
                return 0;
            }
            //看第一位是不是负数
            if(str.charAt(0)=='-'){
                reverse=true;
                str=str.substring(1,str.length());
            }else if(str.charAt(0)=='+'){
                reverse=false;
                str=str.substring(1,str.length());
            }

            //将字符串切割开然后放进去 字符串建造器
            StringBuilder build=new StringBuilder();
            for(int i=0;i<str.length();i++){
              char at=str.charAt(i);
                if(at-'0'<=9&&at-'0'>=0){
                    build.append(at);
                }else{
                    break;
                }
            }
            //如果长度为0 那么
            if(build.length()==0){
                return result;
            }
            //如果数值大于int的最大值
            long tempResult=0;
            //如果超过了返回integer最大值
            for(int i=0;i<build.length();i++){
                tempResult=tempResult*10+Integer.valueOf(build.charAt(i)-'0');
                if(tempResult>Integer.MAX_VALUE){
                    if(reverse){
                        return Integer.MIN_VALUE;
                    }else{
                        return Integer.MAX_VALUE;
                    }
                }
            }     
            //将long转成int 然后取反 返回
            result=(int)tempResult;
            if(reverse){
                result=-result;
            }
            return result;
    }
}

字符串轮转

字符串轮转。给定两个字符串s1和s2,请编写代码检查s2是否为s1旋转而成(比如,waterbottle是erbottlewat旋转后的字符串)。

示例1:

输入:s1 = “waterbottle”, s2 = “erbottlewat”
输出:True
示例2:

输入:s1 = “aa”, s2 = “aba”
输出:False

class Solution {
    public boolean isFlipedString(String s1, String s2) {
        //如果有一个空 那么就返回false
        if(s1==null||s2==null){
            return false;
        }
        //如果长度不相等
        if(s1.length()!=s2.length()){
                return false;
        }
        //将两个 s2进行拼接 因为无论怎么转 只要一拼接 那么就会有出现 一样的
        String ss=s2+s2;
        // 看有没有包含住就可以了
        return ss.contains(s1);

    }
}

无重复字符串的排列组合

无重复字符串的排列组合。编写一种方法,计算某字符串的所有排列组合,字符串每个字符均不相同。

示例1:

输入:S = “qwe”
输出:[“qwe”, “qew”, “wqe”, “weq”, “ewq”, “eqw”]
示例2:

输入:S = “ab”
输出:[“ab”, “ba”]

 
 
 class Solution {
     List<String> list = new ArrayList<String>();
     StringBuffer s=new StringBuffer();
        
    public String[] permutation(String S) {
        dfs(S,list,s);
        return list.toArray(new String[list.size()]);
    }


    public void dfs(String S,List<String> list,StringBuffer s){
        if(s.length() == S.length()){
            list.add(new String(s));
            return;
        }
        for(int i=0;i<S.length();i++){
            String zz=new String(s);
            if(zz.contains(S.charAt(i)+"")){
                continue;
            }
            s.append(S.charAt(i));
            dfs(S,list,s);
            s.deleteCharAt(s.length()-1);
        }
        //没有看懂
    }
}
 
 

有重复字符串的排列组合

有重复字符串的排列组合。编写一种方法,计算某字符串的所有排列组合。

示例1:

输入:S = “qqe”
输出:[“eqq”,”qeq”,”qqe”]
示例2:

输入:S = “ab”
输出:[“ab”, “ba”]

 class Solution {

    LinkedList<String> list= new LinkedList<String>();
    public String[] permutation(String S) {
        dfs(S.toCharArray(),0);
        return list.toArray(new String[0]);
    }


     public void  dfs(char[] c,int k){
        if(k==c.length){
            list.add(new String(c));
            return;
        }
        HashSet<Character> set= new HashSet<>();
        for(int i=k;i<c.length;i++){
            if(!set.contains(c[i])){
                set.add(c[i]);
                swap(c,i,k);
                dfs(c,k+1);
                swap(c,i,k);
            }
        }
        //这个题还没有
    }


    public void swap(char[] c,int x,int y){
        char  temp=c[x];
        c[x]=c[y];
        c[y]=temp;
    }
}
 

二叉树的中序遍历

给定一个二叉树的根节点 root ,返回它的 中序 遍历。

 

示例 1:

输入:root = [1,null,2,3]
输出:[1,3,2]
示例 2:

输入:root = []
输出:[]
示例 3:

输入:root = [1]
输出:[1]
示例 4:

输入:root = [1,2]
输出:[2,1]
示例 5:

输入:root = [1,null,2]
输出:[1,2]


/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        //搞个列表
         ArrayList<Integer> list =new  ArrayList<Integer>();

         //如果为空就返回空
         if(root==null){
             return list;
         }
        rebuildTree(root,list);
        return list;
    }

    public void rebuildTree(TreeNode root,ArrayList<Integer> list){
        //如果为空就是返回这个是定递归的退出条件
        if(root==null){
           return;
        }
        //如果左子树不为空 那么就将左子树放进去
        if(root.left!=null){
        rebuildTree(root.left,list);
        }
        //放一个根节点
        list.add(root.val);
        //如果右子树不为空 那么就将右子树放进去
        if(root.right!=null){
        rebuildTree(root.right,list);
        }



    }
}

验证二叉搜索树

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效 二叉搜索树定义如下:

节点的左子树只包含 小于 当前节点的数。
节点的右子树只包含 大于 当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。  

示例 1:

输入:root = [2,1,3]
输出:true
示例 2:

输入:root = [5,1,4,null,null,3,6]
输出:false
解释:根节点的值是 5 ,但是右子节点的值是 4

class Solution {
    public boolean isValidBST(TreeNode root) {
        //递归  传一个最小和一个最大
        return isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE);
    }

    public boolean isValidBST(TreeNode node, long lower, long upper) {
        //如果为空返回true
        if (node == null) {
            return true;
        }
    //这个值小于下界 或者这个值大于上界就返回false
        if (node.val <= lower || node.val >= upper) {
            return false;
        }
        //继续分隔两边的根进行
        return isValidBST(node.left, lower, node.val) && isValidBST(node.right, node.val, upper);
    }
}

二叉树的层序遍历

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

 

示例 1:

输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]
示例 2:

输入:root = [1]
输出:[[1]]
示例 3:

输入:root = []
输出:[]

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
     ArrayList<List<Integer>> list= new ArrayList<List<Integer>>();
            // 如果为空 返回空
            if(root==null){
                return list;
            }
        //队列
        LinkedBlockingQueue<TreeNode> queue=new LinkedBlockingQueue<TreeNode>();
        //先加一个根进去
        queue.add(root);
        //当根不为空的时候
        while(!queue.isEmpty()){
            ArrayList<Integer> tempList=new ArrayList<Integer>();
            //先拿出目前长度
            int size=queue.size();
            //长度大于0的时候
            while(size>0){
                //从队列中拉一个出来
            TreeNode node=queue.poll();
            //放进去列表中
            tempList.add(node.val);
            //队列的左边不为空 加入
            if(node.left!=null){
                queue.add(node.left);
            }
            //队列的右边不为空 加入
            if(node.right!=null){
                queue.add(node.right);
            }
            //长度一直在递减
              --size;
            }
            //列表加入这个字符串
            list.add(tempList);
        }
        //列表返回
        return list;
    }
}

平衡二叉树

给定一个二叉树,判断它是否是高度平衡的二叉树。

本题中,一棵高度平衡二叉树定义为:

一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。

 

示例 1:

输入:root = [3,9,20,null,null,15,7]
输出:true
示例 2:

输入:root = [1,2,2,3,3,null,null,4,4]
输出:false
示例 3:

输入:root = []
输出:true


/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isBalanced(TreeNode root) {
        //如果为空那么可以
            if(root==null){
                return true;
            }

        //左右子树的深度
            int left=depth(root.left);
            int right=depth(root.right);
            //还有子树的左右子树也需要是平衡树
            return Math.abs(left-right)<=1&&isBalanced(root.left)&&isBalanced(root.right);
    }

//算出以一个树为基础的深度为多少
    public int depth(TreeNode root){
            if(root==null){
                return 0;
            }

            return Math.max(depth(root.left),depth(root.right))+1;
    }
}

求根节点到叶节点数字之和

给你一个二叉树的根节点 root ,树中每个节点都存放有一个 0 到 9 之间的数字。
每条从根节点到叶节点的路径都代表一个数字:

例如,从根节点到叶节点的路径 1 -> 2 -> 3 表示数字 123 。
计算从根节点到叶节点生成的 所有数字之和 。

叶节点 是指没有子节点的节点。

 

示例 1:

输入:root = [1,2,3]
输出:25
解释:
从根到叶子节点路径 1->2 代表数字 12
从根到叶子节点路径 1->3 代表数字 13
因此,数字总和 = 12 + 13 = 25
示例 2:

输入:root = [4,9,0,5,1]
输出:1026
解释:
从根到叶子节点路径 4->9->5 代表数字 495
从根到叶子节点路径 4->9->1 代表数字 491
从根到叶子节点路径 4->0 代表数字 40
因此,数字总和 = 495 + 491 + 40 = 1026

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public int sumNumbers(TreeNode root) {
            return count(root,0);
    }

    //递归调用左边和右边相加
    int count(TreeNode root,int sum){
            if(root==null){
                return 0;
            }else if(root.left==null&&root.right==null){
                return sum*10+root.val;
            }else{
                return count(root.left,sum*10+root.val)+count(root.right,sum*10+root.val);
            }
        
    }
}

二叉树的前序遍历

给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

 

示例 1:

输入:root = [1,null,2,3]
输出:[1,2,3]
示例 2:

输入:root = []
输出:[]
示例 3:

输入:root = [1]
输出:[1]
示例 4:

输入:root = [1,2]
输出:[1,2]
示例 5:

输入:root = [1,null,2]
输出:[1,2]

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        //搞个列表
        ArrayList<Integer> list = new ArrayList<Integer>();
        //如果为空就直接返回
        if(root==null){
            return list;
        }
        //递归
        createTree(root,list);
        return list;
    }


    public void  createTree(TreeNode root, ArrayList list){
            if(root==null){
                return;
            }
            //注意顺序 先序就把根放前面
            list.add(root.val);
            //如果左子树不为空 递归左子树
            if(root.left!=null){
                createTree(root.left,list);
            }
            //如果右子树不为空 递归右子树
            if(root.right!=null){
                createTree(root.right,list);
            }
    }
}

二叉树的后序遍历

给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历

示例 1:

输入:root = [1,null,2,3]
输出:[3,2,1]

示例 2:

输入:root = []
输出:[]
示例 3:

输入:root = [1]
输出:[1]

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    //这个题跟前序遍历 和中序遍历原理一模一样
    public List<Integer> postorderTraversal(TreeNode root) {
            ArrayList<Integer> list= new ArrayList<Integer>();
            if(root==null){
                return list;
            }
            createTree(root,list);

            return list;
    }

    public void createTree(TreeNode root,ArrayList list){
        if(root==null){
            return ;
        }
        if(root.left!=null){
            createTree(root.left,list);
        }
        if(root.right!=null){
            createTree(root.right,list);
        }

        list.add(root.val);
    }
}

二叉树的右视图

给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

示例 1:

输入: [1,2,3,null,5,null,4]
输出: [1,3,4]
示例 2:

输入: [1,null,3]
输出: [1,3]
示例 3:

输入: []
输出: []

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> rightSideView(TreeNode root) {
    //搞一个作为结果
     ArrayList<Integer> result=new ArrayList<Integer>();
     if(root==null){
         return result;
     }
     //搞个列表存储
     ArrayList<List<Integer>> list=new ArrayList<List<Integer>>();
    //搞个队列
     LinkedBlockingQueue<TreeNode> queue= new LinkedBlockingQueue<TreeNode>();
     //队列接入一个根
     queue.add(root);
     //根不为空的时候  这个模型就是把树转成了列表
     while(!queue.isEmpty()){
         int size=queue.size();
        ArrayList<Integer> tempList= new ArrayList<Integer>();
         while(size>0){
            TreeNode tree=queue.poll();
            if(tree.left!=null){
                queue.add(tree.left);
            }
            if(tree.right!=null){
                queue.add(tree.right);
            }
            tempList.add(tree.val);
             size--;
         }
         list.add(tempList);
     }


        //把列表的最后一个放进另外一个列表即可
     for(int i=0;i<list.size();i++){
        List<Integer> tempList=list.get(i);
         result.add(tempList.get(tempList.size()-1));
      }
          return result;
    }
}

完全二叉树的节点个数

给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。

完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。

 

示例 1:

输入:root = [1,2,3,4,5,6]
输出:6
示例 2:

输入:root = []
输出:0
示例 3:

输入:root = [1]
输出:1

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public int countNodes(TreeNode root) {
        //如果为空 那么返回0
        if(root==null){
            return 0;
        }
    //搞一个队列
     LinkedBlockingQueue<TreeNode> queue=new LinkedBlockingQueue<TreeNode>();
    //队列加入一个根节点
    queue.add(root);
    //列表
     ArrayList<Integer> list=new ArrayList<Integer>();
     //当队列不为空的时候
        while(!queue.isEmpty()){
            //队列长度
            int size=queue.size();
            //当大小大于0
            while(size>0){
               TreeNode tree=queue.poll();
               //将左右子树加入
                if(tree.left!=null){
                    queue.add(tree.left);
                }
                if(tree.right!=null){
                    queue.add(tree.right);
                }
                //列表加入
                list.add(tree.val);
                size--;
            }
        }
        //这个数字就是节点的数字
            return list.size();
    }
}

二叉搜索树中第K小的元素

给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 个最小元素(从 1 开始计数)。

 

示例 1:

输入:root = [3,1,4,null,2], k = 1
输出:1
示例 2:

输入:root = [5,3,6,2,4,null,null,1], k = 3
输出:3

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public int kthSmallest(TreeNode root, int k) {
         ArrayList<Integer> list=new ArrayList<Integer>();
        if(root==null){
            return 0;
        }
        //这个还是那个层次遍历的模型 然后搞成一个列表 然后搞成一个数组,然后对数组进行排序 然后 就可以看到第k小的数字了
        LinkedBlockingQueue<TreeNode> queue=new LinkedBlockingQueue<TreeNode>();
        queue.add(root);
        while(!queue.isEmpty()){
            int size=queue.size();
             while(size>0){
                TreeNode tree= queue.poll();
            
                if(tree.left!=null){
                    queue.add(tree.left);
                }

                if(tree.right!=null){
                    queue.add(tree.right);
                }
                 list.add(tree.val);
                --size;
            }
        }
        int[] arr=new int[list.size()];

        for(int i=0;i<list.size();i++){
            arr[i]=list.get(i);
        }

        Arrays.sort(arr);


        return arr[k-1];
    }
}

二叉树的最近公共祖先

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

 

示例 1:

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点 5 和节点 1 的最近公共祖先是节点 3 。
示例 2:

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出:5
解释:节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。
示例 3:

输入:root = [1,2], p = 1, q = 2
输出:1

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
     HashMap<Integer, TreeNode> parent = new HashMap<>();
    HashSet<Integer> visited = new HashSet<>();
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        dfs(root);

        while (p != null) {
            visited.add(p.val);
            p = parent.get(p.val);
        }

        while (q != null) {
            if (visited.contains(q.val)) {
                return q;
            }
            //从下往上访问父节点  map存的是父节点
            q = parent.get(q.val);
        }
        return null;
    }
    
      public void dfs(TreeNode root) {
        if (root.left != null) {
            parent.put(root.left.val, root);
            dfs(root.left);
        }
        if (root.right != null) {
            parent.put(root.right.val, root);
            dfs(root.right);
        }
        //没看懂
    }
}


二叉树的直径

给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。

 

示例 :
给定二叉树

      1
     / \
    2   3
   / \     
  4   5    

返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    int ans;
    public int diameterOfBinaryTree(TreeNode root) {
        ans = 1;
        depth(root);
        return ans - 1;
    }
    public int depth(TreeNode node) {
        if (node == null) {
            return 0; // 访问到空节点了,返回0
        }
        int L = depth(node.left); // 左儿子为根的子树的深度
        int R = depth(node.right); // 右儿子为根的子树的深度
        ans = Math.max(ans, L+R+1); // 计算d_node即L+R+1 并更新ans
        return Math.max(L, R) + 1; // 返回该节点为根的子树的深度
    }
}

合并二叉树

给你两棵二叉树: root1 和 root2 。

想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。

返回合并后的二叉树。

注意: 合并过程必须从两个树的根节点开始。

 

示例 1:

输入:root1 = [1,3,2,5], root2 = [2,1,3,null,4,null,7]
输出:[3,4,5,5,4,null,7]
示例 2:

输入:root1 = [1], root2 = [1,2]
输出:[2,2]

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        //如果2为空 返回1
        if(root2==null){
               return root1;
        }
        //如果1位空 返回2
        if(root1==null){
               return root2;
        }
        //如果都不会空 相加
        root1.val=root1.val+root2.val;

        //递归 左边和左边
        root1.left=mergeTrees(root1.left,root2.left);
        //递归 右边和右边
        root1.right=mergeTrees(root1.right,root2.right);
        return root1;
    }

}

二叉树的镜像

请完成一个函数,输入一个二叉树,该函数输出它的镜像。

例如输入:

     4
   /  
  2     7
 / \   /
1   3 6   9
镜像输出:

     4
   /  
  7     2
 / \   /
9   6 3   1

 

示例 1:

输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode mirrorTree(TreeNode root) {
        //如果为空那么返回为空
         if(root==null){
            return null;
          }
            //这个本质上是调换两个子树
            TreeNode leftTree= root.left;
            TreeNode temp=leftTree;
            root.left= root.right;
            root.right=temp;
            //然后递归继续去换子树
            mirrorTree(root.left);
            mirrorTree(root.right);

        return root;
    }
}

对称的二叉树

请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。

例如,二叉树 [1,2,2,3,4,4,3] 是对称的。

    1
   /
  2   2
 / \ /
3  4 4  3
但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:

    1
   /
  2   2
   \  
   3    3

 

示例 1:

输入:root = [1,2,2,3,4,4,3]
输出:true
示例 2:

输入:root = [1,2,2,null,3,null,3]
输出:false


/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isSymmetric(TreeNode root) {
        //如果为空也是一个镜像函数
          if(root==null){
              return true;
          }
    
        //判断是否镜像
        return isSame(root,root);

    }

    public boolean isSame(TreeNode root,TreeNode monitorTree){
        //如果为空可以
       if(root==null&&monitorTree==null){
           return true;
       }
        //如果有一个不为空 一个为空不行
       if(root==null||monitorTree==null){
           return false;
       }

        //如果值相等 那么  对应镜像的值去匹配  左子树的跟另外一个右子树比 右子树的跟左子树比
        if(root.val==monitorTree.val){
            return isSame(root.left,monitorTree.right)&&isSame(root.right,monitorTree.left);
        }else{
            return false;
        }
    }
}

从上到下打印二叉树 II

从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。

 

例如:
给定二叉树: [3,9,20,null,null,15,7],

3

/
9 20
/
15 7
返回其层次遍历结果:

[
[3],
[9,20],
[15,7]
]

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        //存储结果的列表
       ArrayList<List<Integer>>  result=    new ArrayList<List<Integer>>();
       //如果为空的话 直接返回
       if(root==null){
           return result;
       }



        LinkedBlockingQueue<TreeNode> queue= new LinkedBlockingQueue<TreeNode>();
        //队列中放进一个根的数值
        queue.add(root);
        //如果不为空那么就继续
        while(!queue.isEmpty()){
            //先取出当期的队列长度
            int size =queue.size();
            //搞一个列表
            ArrayList<Integer> tempList=new ArrayList<Integer>();
            //如果队列长度大于0
            while(size>0){ 
                //从队列中搞一个出来
                TreeNode tree=queue.poll();
                //如果左子树不为空就放进去
                if(tree.left!=null){
                    queue.add(tree.left);
                }
                //如果右子树不为空也放进去
                if(tree.right!=null){
                    queue.add(tree.right);
                }
                //把值放到一个列表之中
                tempList.add(tree.val);
                //大小减一   
                --size;
            }
            //将结果返回回去
            result.add(tempList);
        }
        return result;
    }
}


从上到下打印二叉树 III

请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。

 

例如:
给定二叉树: [3,9,20,null,null,15,7],

3

/
9 20
/
15 7
返回其层次遍历结果:

[
[3],
[20,9],
[15,7]
]

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        //搞一个结果的列表
       ArrayList<List<Integer>>  result=new ArrayList<List<Integer>>();
       //如果为空返回
        if(root==null){
            return result;
        }
        //这个是要不要反转的标志
        boolean flag=false;
        //队列
      LinkedBlockingQueue<TreeNode> queue = new LinkedBlockingQueue<TreeNode>();
      //先放一个根目录
      queue.add(root);
        //当队列不为空的时候
        while(!queue.isEmpty()){
            //队列长度
            int size=queue.size();
            //临时的数组长度
        ArrayList<Integer> list=new  ArrayList<Integer>();
            while(size>0){
                //从队列拿出第一个
                TreeNode tree=queue.poll();
                //如果存在左右子树就放进去
                if(tree.left!=null){
                    queue.add(tree.left);
                }
                if(tree.right!=null){
                    queue.add(tree.right);
                }
                //列表放这个数的值
                list.add(tree.val);
                //
                --size;
            }
            //控制是否需要反转
          if(flag){
            Collections.reverse(list);
          }
          //标志位取反
          flag=!flag;
          //将结果加进去
           result.add(list);
        }

        return result;
    }
}

二叉树中和为某一值的路径

给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

叶子节点 是指没有子节点的节点。

 

示例 1:

输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:[[5,4,11,2],[5,8,4,5]]
示例 2:

输入:root = [1,2,3], targetSum = 5
输出:[]
示例 3:

输入:root = [1,2], targetSum = 0
输出:[]

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    //搞个结果的容器
    List<List<Integer>> result = new ArrayList<>();
    public List<List<Integer>> pathSum(TreeNode root, int target) {
        //深度优先
        dfs(root,target,new ArrayList());
        return result;
    }

    public void dfs(TreeNode root, int target,List list){
        //如果为空的话就返回
            if(root==null){
                return ;
            }
            //列表加入根的值
            list.add(root.val);
            //如果这个值是跟目标匹配
            if(root.left==null&&root.right==null&&root.val==target){
                result.add(new ArrayList<>(list));
            }
            //进行左边和右边目标值
            dfs(root.left,target-root.val,list);
            dfs(root.right,target-root.val,list);
            //列表删除前面那个
            list.remove(list.size()-1);

    }



}

二叉树的深度

输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。

例如:

给定二叉树 [3,9,20,null,null,15,7],

3

/
9 20
/
15 7
返回它的最大深度 3 。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int maxDepth(TreeNode root) {
    //搞一个队列来存树
    LinkedBlockingQueue<TreeNode> queue=new LinkedBlockingQueue<TreeNode>();
    if(root==null){
        return 0;
    }
    //先加一个根进去
    queue.add(root);
    //深度为0
    int depth=0;

    //当队列不为空的时候继续搞
    while(!queue.isEmpty()){
        int size = queue.size();
        //当队列长度大于0的时候
        while(size>0){
            //队列搞一个出来
           TreeNode tree= queue.poll();
           //当队列不为空  队列加入
            if(tree.left!=null){
                queue.add(tree.left);
            }
            //当队列不为空 队列加入
            if(tree.right!=null){
                queue.add(tree.right);
            }
            //队列递减
            size--;
        }
        //当走出一个循环的时候 深度会加1
        depth++;
    }
    return depth;
    }
}

平衡二叉树

输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。

 

示例 1:

给定二叉树 [3,9,20,null,null,15,7]

3

/
9 20
/
15 7
返回 true 。

示例 2:

给定二叉树 [1,2,2,3,3,null,null,4,4]

   1
  / \
 2   2
/ \

3 3
/
4 4
返回 false 。


/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isBalanced(TreeNode root) {
        if(root==null){
            return true;
        }
        // 
        //左树的最大深度
        int left=depth(root.left);
        //右子树的最大深度
        int right=depth(root.right);
        //其实就是一直找 以这个根为节点的左右最大深度
        return Math.abs(left-right)<=1&&isBalanced(root.left)&&isBalanced(root.right);
    }

        //这个功能主要是以某一个根为节点的最大深度
    public int depth(TreeNode root){
            if(root==null){
                return 0;
            }
            return Math.max(depth(root.left),depth(root.right))+1;
    }

}

求和路径

给定一棵二叉树,其中每个节点都含有一个整数数值(该值或正或负)。设计一个算法,打印节点数值总和等于某个给定值的所有路径的数量。注意,路径不一定非得从二叉树的根节点或叶节点开始或结束,但是其方向必须向下(只能从父节点指向子节点方向)。

示例:
给定如下二叉树,以及目标和 sum = 22,

          5
         / \
        4   8
       /   / \
      11  13  4
     /  \    / \
    7    2  5   1

返回:

3
解释:和为 22 的路径有:[5,4,11,2], [5,8,4,5], [4,11,7]

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    List<List<Integer>> result=new ArrayList<>();
    public int pathSum(TreeNode root, int sum) {
        //当根为空的时候 返回0
        if(root==null){
            return 0;
        }
        //深度优先
        dfs(root,sum,new ArrayList()); 
        //而且要递归根的左边和右边
        pathSum(root.left,sum);
        //递归根的左边和右边
        pathSum(root.right,sum);
        return result.size();
    }



    //深度优先的套路 这个模型主要是用来解决路径的值等于某一个值的
    public void dfs(TreeNode root,int target,ArrayList list){
        //如果为空返回
        if(root==null){
            return;
        }
        //列表加入一个值
        list.add(root.val);   
        //深度递归 将目标值改成目标值减去树的根值
        dfs(root.left,target-root.val,list);
        dfs(root.right,target-root.val,list);
        //如果目标等于跟的值 那么这个结果加入列表
        if(target==root.val){
            result.add(new ArrayList(list));
        }
        //将值减去1 达到一个回溯的效果
        list.remove(list.size()-1);
    }
}

链表

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

 

示例 1:

输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]
示例 2:

输入:head = [1], n = 1
输出:[]
示例 3:

输入:head = [1,2], n = 1
输出:[1]

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        //基本的思路就是把链表转成数组 然后删掉倒数几个 然后再把数组还原回去
          ArrayList<Integer> list=new ArrayList<Integer>();

         while(head!=null){
             list.add(head.val);
             head=head.next;
         }

        list.remove(list.size()-n);           
        if(list.size()<=0){
            return null;
        }        

        ListNode root=new  ListNode(list.get(0));
        ListNode index=root;
        for(int i=1;i<list.size();i++){
            System.out.print(list.get(i));
            ListNode  temp =  new ListNode(list.get(i));
            index.next=temp;
            index=temp;
        }
        return root;
    }
}

合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 

 

示例 1:

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
示例 2:

输入:l1 = [], l2 = []
输出:[]
示例 3:

输入:l1 = [], l2 = [0]
输出:[0]


/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        //如果list2 为空 返回list1
        if(list2==null){
            return list1;
        }
        //如果list1为空返回list2
        if(list1==null){
            return list2;
        }
        //搞两个数组存储
       ArrayList<Integer> arrayList1= new ArrayList<Integer>();
       ArrayList<Integer> arrayList2= new ArrayList<Integer>();
        //当列表不为空的时候 装进去数组
        while(list1!=null){
               arrayList1.add(list1.val);
               list1=list1.next; 
        }  
        //当列表2不为空的时候装进去数组
        while(list2!=null){
            arrayList2.add(list2.val);
            list2=list2.next;
        }

        int length=arrayList1.size()+arrayList2.size();

        int[] arr=new int[length];
        //搞一个可以容纳这么多的数组
        for(int i=0;i<arrayList1.size();i++){
            arr[i]=arrayList1.get(i);
        }
        //都装进去
        for(int i=arrayList1.size();i<(arrayList1.size()+arrayList2.size());i++){
            arr[i]=arrayList2.get(i-arrayList1.size());
        }
        //对数组进行排序
        Arrays.sort(arr);

       ListNode root= new ListNode(arr[0]);
       ListNode tempNode=root;
        //将 数组按列表复原
        for(int i=1;i<arr.length;i++){
        ListNode node= new ListNode(arr[i]);
        tempNode.next=node;
        tempNode=node;
        }
        return root;
    }
}

合并K个升序链表

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

 

示例 1:

输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
1->4->5,
1->3->4,
2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6
示例 2:

输入:lists = []
输出:[]
示例 3:

输入:lists = [[]]
输出:[]

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    //思路还是将 链表转成了所有数组 然后组装回去一个链表
    public ListNode mergeKLists(ListNode[] lists) {
        if(lists==null||lists.length==0||(lists.length==1&&lists[0]==null)){
            return null;
        }
      ArrayList<Integer> list=new ArrayList<Integer>();
      for(int i=0;i<lists.length;i++){
        ListNode node=  lists[i];
        while(node!=null){
            list.add(node.val);
            node=node.next;
        }
      }
        int length=list.size();
        if(length<=0){
            return null;
        }

        int[] arr = new int[length];

        for(int i=0;i<list.size();i++){
            arr[i]=list.get(i);
        }
        Arrays.sort(arr);

   

      ListNode root= new ListNode(arr[0]);
      ListNode index=root;


      for(int i=1;i<arr.length;i++){
          System.out.print(arr[i]);
         ListNode node= new ListNode(arr[i]);
         index.next=node;
         index=node;
      }


        return root;

    }
}

删除排序链表中的重复元素 II

给定一个已排序的链表的头 head , 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。

 

示例 1:

输入:head = [1,2,3,3,4,4,5]
输出:[1,2,5]
示例 2:

输入:head = [1,1,1,2,3]
输出:[2,3]

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode deleteDuplicates(ListNode head) {

        if(head==null||head.next==null){
            return head;
        }

        HashMap<Integer,Integer> map= new HashMap<Integer,Integer>();
        ArrayList<Integer>  list= new ArrayList<>();

        while(head!=null){
            if(!list.contains(head.val)){
                list.add(head.val);
            }

            if(map.get(head.val)==null){
                map.put(head.val,1);
            }else{
                map.put(head.val,map.get(head.val)+1);
            }
            head=head.next;
        }


        // for(int i=0;i<list.size();i++){
        //     System.out.print(list.get(i));
        //     System.out.print(map.get(list.get(i)));
        // }
        ListNode result=null;
        ListNode index=null;

        for(int i=0;i<list.size();i++){
             if(map.get(list.get(i))==1){
                if(result==null){
                    result= new ListNode(list.get(i));
                    index=result;
                }else{
                    System.out.print(list.get(i));
                     ListNode temp= new ListNode(list.get(i));
                     index.next=temp;
                     index=index.next;
                }             
             }
        }
        //暂时没有时间看看
        return result;

    }
}

删除排序链表中的重复元素

给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。

 

示例 1:

输入:head = [1,1,2]
输出:[1,2]
示例 2:

输入:head = [1,1,2,3,3]
输出:[1,2,3]

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
     public ListNode deleteDuplicates(ListNode head) {
        if(head==null){
            return null;
        }
        //当node不为空的时候就会往下移动,但是只有当下一个不等于当前这个的时候才会移动
           ListNode temp=head;
           while(temp!=null){
               if(temp.next!=null){
                   if(temp.val==temp.next.val){
                       temp.next=temp.next.next;
                   }
               }
               if(temp.next==null||temp.next.val!=temp.val){
                    temp=temp.next;
               }                                   
           }
        return head;
    }
}

反转链表 II

给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。  

示例 1:

输入:head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]
示例 2:

输入:head = [5], left = 1, right = 1
输出:[5]

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseBetween(ListNode head, int left, int right) {

        ArrayList<Integer> list=new ArrayList<Integer>();
        ListNode temp=head;

        while(temp!=null){
            list.add(temp.val);
            temp=temp.next;
        }

        int[] arr=new int[list.size()];

       for(int i=0;i<list.size();i++){
            arr[i]=list.get(i);
        }


 
      

       for(int i=0;i<(right-left+1)/2;i++){
          int tempValue=arr[left+i-1];
          arr[left+i-1]=arr[right-i-1];
          arr[right-i-1]=tempValue;
       }

        for(int i=0;i<list.size();i++){
             System.out.print(arr[i]);
        }
       

        ListNode result=null;
        ListNode index=null;

        for(int i=0;i<arr.length;i++){
                if(result==null){
                    result= new ListNode(arr[i]);
                    index=result;
                }else{
                    index.next=new ListNode(arr[i]);
                    index=index.next;
                }
        }
        //没有看懂
       



        return result;
    }
}

环形链表

给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

如果链表中存在环 ,则返回 true 。 否则,返回 false 。

 

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:

输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:

输入:head = [1], pos = -1
输出:false
解释:链表中没有环。

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public boolean hasCycle(ListNode head) {
      //如果为空那就返回
      if(head==null){
          return false;
      }
     ListNode temp;
     //将链表放在中间
      temp=head;
      //搞两个中间件
      ListNode temp1=temp;
      ListNode temp2=temp;
      //当这个不为空或者下一个不为空
      while(temp2!=null&&temp2.next!=null){
          temp1=temp1.next;
          temp2=temp2.next.next;
          //如果是环形的话他们就一定会重复 如果不是环形的 那么跑一次就没有了
          if(temp1==temp2){
              return true;
          }
      }
      return  false;
    }
}


LRU 缓存

请你设计并实现一个满足  LRU (最近最少使用) 缓存 约束的数据结构。
实现 LRUCache 类:
LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。
函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。

 

示例:

输入
[“LRUCache”, “put”, “put”, “get”, “put”, “get”, “put”, “get”, “get”, “get”]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出
[null, null, null, 1, null, -1, null, -1, 3, 4]

解释
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1); // 返回 1
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2); // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1); // 返回 -1 (未找到)
lRUCache.get(3); // 返回 3
lRUCache.get(4); // 返回 4


class LRUCache {
    //要搞这个LUR需要搞一个map加一个双向链表
    private int capacity;
    //容量大小
    private int size = 0;
    //map
    private Map<Integer, Entry> cache = new HashMap<Integer, Entry>();
    //这个是双向链表的头和尾
    private Entry head, tail;

    public LRUCache(int capacity) {
        this.capacity = capacity;
        this.size = 0;
        head = new Entry();
        tail = new Entry();
        head.next = tail;
        tail.prev = head;
    }
//  获取的时候从map取出来 发现为空就返回 不为空就插入到头那边
    public int get(int key) {
        Entry node = cache.get(key);
        if (node == null) {
            return -1;
        }
        moveToHead(node);
        return node.value;
    }

    //插入到头那边就是先从尾巴删掉 然后加入到头那边
    private void moveToHead(Entry node) {
        removeNode(node);
        addToHead(node);
    }
    //加入到头那边  添加节点就是 这个节点的前一个为头,节点的下一个是头的下一个  头的前一个为这个  头的下一个为这个
    private void addToHead(Entry node) {
        node.prev = head;
        node.next = head.next;
        head.next.prev = node;
        head.next = node;
    }
    //删除这个节点   删除节点就是 这个节点的前面的下一个变成这的下一个    这个节点的下一个的前一个变成节点的前一个
    private void removeNode(Entry node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }

    //放进去的话 从map拿出来 如果存在就刷新  如果不存在的话 就加入 加入的时候如果发现已经超过了最大的话那么就删掉最后一个
    public void put(int key, int value) {
        Entry node = cache.get(key);
        if (node == null) {
            // 如果 key 不存在,创建一个新的节点
            Entry newNode = new Entry(key, value);
            // 添加进哈希表
            cache.put(key, newNode);
            // 添加至双向链表的头部
            addToHead(newNode);
            ++size;
            if (size > capacity) {
                // 如果超出容量,删除双向链表的尾部节点
                Entry tail = removeTail();
                // 删除哈希表中对应的项
                cache.remove(tail.key);
                --size;
            }
        } else {
            // 如果 key 存在,先通过哈希表定位,再修改 value,并移到头部
            node.value = value;
            moveToHead(node);
        }
    }
    //删掉最后一个就是双向链表的尾结点的前一个
    private Entry removeTail() {
        Entry res = tail.prev;
        removeNode(res);
        return res;
    }


    class Entry {
        int key;
        int value;

        Entry prev;
        Entry next;

        public Entry(int key, int value) {
            this.key = key;
            this.value = value;
        }

        public Entry() {

        }

    }
}

排序链表

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。

 

示例 1:

输入:head = [4,2,1,3]
输出:[1,2,3,4]
示例 2:

输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]
示例 3:

输入:head = []
输出:[]

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode sortList(ListNode head) {
        if(head==null){
            return null; 
            }
    //这个思路是把链表搞成数组 然后数组排序 然后再组装成链表
      ArrayList<Integer> list=  new ArrayList<Integer>();

         while(head!=null){
             list.add(head.val);
             head=head.next;
           }

            int[] arr= new  int[list.size()];
           
           for(int i=0;i<list.size();i++){
              arr[i]=list.get(i);  
           }
           
           Arrays.sort(arr);
        ListNode root=new ListNode(arr[0]);
        ListNode index=root;

        for(int i=1;i<arr.length;i++){
            System.out.print(arr[i]);

             ListNode node=   new ListNode(arr[i]);
             index.next=node;
             index=node;
        }

        return root;

    }
}

奇偶链表

给定单链表的头节点 head ,将所有索引为奇数的节点和索引为偶数的节点分别组合在一起,然后返回重新排序的列表。

第一个节点的索引被认为是 奇数 , 第二个节点的索引为 偶数 ,以此类推。

请注意,偶数组和奇数组内部的相对顺序应该与输入时保持一致。

你必须在 O(1) 的额外空间复杂度和 O(n) 的时间复杂度下解决这个问题。

 

示例 1:

输入: head = [1,2,3,4,5]
输出: [1,3,5,2,4]
示例 2:

输入: head = [2,1,3,5,6,4,7]
输出: [2,3,6,7,1,5,4]

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode oddEvenList(ListNode head) {
        if(head==null||head.next==null){
            return head;
        }

        ListNode l1=new ListNode(0);
        ListNode l2=new ListNode(0);
        ListNode tempHead=head;
        ListNode temp1=l1;
        ListNode temp2=l2;
        boolean isOdd=true;
        
        while(tempHead!=null){
        if(isOdd){
                l1.next=tempHead;
                l1=l1.next;
            }else{
                l2.next=tempHead;
                l2=l2.next;
            } 
            isOdd=!isOdd;
            tempHead=tempHead.next;
        }
           if(l1.next!=null){
                l1.next=null;
            }
            if(l2.next!=null){
                l2.next=null;
            }
            l1.next=temp2.next;
            return temp1.next;
    }
}

两数相加 II

给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。

你可以假设除了数字 0 之外,这两个数字都不会以零开头。

 

示例1:

输入:l1 = [7,2,4,3], l2 = [5,6,4]
输出:[7,8,0,7]
示例2:

输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[8,0,7]
示例3:

输入:l1 = [0], l2 = [0]
输出:[0]

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        //搞两个栈来存储 因为刚好满足这个特性
         Stack<Integer>  stack1=    new Stack<Integer>();
            Stack<Integer>  stack2=    new Stack<Integer>();
            while(l1!=null){
                stack1.push(l1.val);
                l1=l1.next;
            }

            while(l2!=null){
                stack2.push(l2.val);
                l2=l2.next;
            }
            //进位的标志
            int carry=0;
            //根
            ListNode head=null;

            while(!stack1.isEmpty()||!stack2.isEmpty()||carry>0){
                //进位的
                int sum=carry;
                //从栈弹一个出来
                sum+=stack1.isEmpty()?0:stack1.pop();
                //从栈弹一个出来
                sum+= stack2.isEmpty()?0:stack2.pop();
                //只取一位
                 ListNode node=new ListNode(sum%10);
                 //下一位指向头
                 node.next=head;
                 //下一个
                 head=node;
                 //除以时
                 carry=sum/10;
            }
                //返回这个头
                return head;
    }
}


链表中倒数第k个节点

输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。

例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。这个链表的倒数第 3 个节点是值为 4 的节点。

示例:

给定一个链表: 1->2->3->4->5, 和 k = 2.

返回链表 4->5.

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode getKthFromEnd(ListNode head, int k) {
    //先把链表放到列表中
      ArrayList<ListNode> list=  new ArrayList<ListNode>();
      while(head!=null){
          list.add(head);
          head=head.next;
      }
      //然后从列表中拿出倒数第几个元素
     return  list.get(list.size()-k);
    }
}

反转链表

定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。

 

示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
    if(head==null){
        return head;
    }
    //先搞一个列表 将链表按值放进去
     ArrayList<Integer> list= new ArrayList<Integer>();
        while(head!=null){
            list.add(head.val);
            head=head.next;
        }
        //对列表进行排序
        Collections.reverse(list);
        // 把列表按链表的方式排序回来
       ListNode root= new ListNode(list.get(0));
       ListNode index=root;
        for(int i=1;i<list.size();i++){
            int temp=list.get(i);
            ListNode tree =new ListNode(temp);
            index.next=tree;
            index=tree;
        }
        return root;
    }
}

输入两个链表,找出它们的第一个公共节点。

如下面的两个链表:

在节点 c1 开始相交。

 

示例 1:

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。  

示例 2:

输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Reference of the node with value = 2
输入解释:相交节点的值为 2 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。  

示例 3:

输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
输入解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
解释:这两个链表不相交,因此返回 null。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        //链表a 链表b
            ListNode  headATemp=headA;
            ListNode  headBTemp=headB;
            //当A 不为空的时候 取出一个A 遍历b 如果遍历到的了话 那么就返回回去
            while(headATemp!=null){
                    while(headBTemp!=null){
                        if(headATemp==headBTemp){
                            return headATemp;
                        }
                        headBTemp=headBTemp.next;
                    }

                    headBTemp=headB;

                headATemp=headATemp.next;
            }

            return null;
    }
}

链表中环的入口节点

给定一个链表,返回链表开始入环的第一个节点。 从链表的头节点开始沿着 next 指针进入环的第一个节点为环的入口节点。如果链表无环,则返回 null。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意,pos 仅仅是用于标识环的情况,并不会作为参数传递到函数中。

说明:不允许修改给定的链表。

 

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:

输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:

输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
       public ListNode detectCycle(ListNode head) {
        if(head==null||head.next==null){
            return null;
        }

        ListNode fastNode=head;
        ListNode slowNode=head;

        while(fastNode != null && fastNode.next != null){
            fastNode=fastNode.next.next;
            slowNode=slowNode.next;
            if(fastNode==slowNode){
                 fastNode = head;
                while(slowNode != fastNode){
                    slowNode = slowNode.next;
                    fastNode = fastNode.next;
                }
                return slowNode;
            }
         
      
        }
        //环在第一个

        return null;

        
    }
}


回文链表

给定一个链表的 头节点 head ,请判断其是否为回文链表。

如果一个链表是回文,那么链表节点序列从前往后看和从后往前看是相同的。

 

示例 1:

输入: head = [1,2,3,3,2,1]
输出: true
示例 2:

输入: head = [1,2]
输出: false

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public boolean isPalindrome(ListNode head) {
        //如果列表为空 返回false
        if(head==null){
            return false;
        }
        //搞一个列表长度
        ArrayList<ListNode> arr=new ArrayList<ListNode>();
        //把链表搞成列表
        while(head!=null){
            arr.add(head);
            head=head.next;
        }

        //看一下列表是不是一个回文树
        for(int i=0;i<arr.size()/2;i++){
            if(arr.get(i).val!=arr.get(arr.size()-1-i).val){
                    return false;
            }
        }
        return true;

    }
}


其他

整数反转

给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。

如果反转后整数超过 32 位的有符号整数的范围 [−231,  231 − 1] ,就返回 0。

假设环境不允许存储 64 位整数(有符号或无符号)。  

示例 1:

输入:x = 123
输出:321
示例 2:

输入:x = -123
输出:-321
示例 3:

输入:x = 120
输出:21
示例 4:

输入:x = 0
输出:0

class Solution {
    public int reverse(int x) {
        if(x==0){
            return 0;
        }
        //这个flag是用来标志负
        boolean flag=false;
        //如果小于0 就取反 标记这个负
        if(x<0){
            flag=true;
            x=-x;
        }
        //搞一个列表
        ArrayList<Integer> list= new ArrayList<Integer>();
        //把数字切割然后放到列表
            while(x>0){
                int last=x%10;
                list.add(last);    
                x=x/10;
            }
            //把列表还原 主要要判断如果大小大于integer 的最大值 那么久返回0
            long result=0;
            for(int i=0;i<list.size();i++){
                   if(result*10+list.get(i)>Integer.MAX_VALUE){
                       return 0;
                   }else{
                      result=result*10+list.get(i); 

                   }
            }
            if(flag){
                result=-result;
            }

        return (int)result;
    }
}

回文数

给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。

回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。例如,121 是回文,而 123 不是。

 

示例 1:

输入:x = 121
输出:true
示例 2:

输入:x = -121
输出:false
解释:从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。
示例 3:

输入:x = 10
输出:false
解释:从右向左读, 为 01 。因此它不是一个回文数。
示例 4:

输入:x = -101
输出:false

class Solution {
    public boolean isPalindrome(int x) {
        //如果数值小于0那么返回false
        if(x<0){
            return false;
        }

        //搞个列表
      ArrayList<Integer> list = new ArrayList<Integer>();
        //当数值大于0的时候 取余10  然后加入列表 然后除以10
      while(x>0){
          int last=x%10;
          list.add(last);
          x=x/10;
      }
        //然后就直接对比
      for(int i=0;i<list.size()/2;i++){
          if(list.get(i)!=list.get(list.size()-1-i)){
              return false;
          }
      }
    return true;
    }
}




x 的平方根

给你一个非负整数 x ,计算并返回 x 的 算术平方根 。

由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。

注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。

 

示例 1:

输入:x = 4
输出:2
示例 2:

输入:x = 8
输出:2
解释:8 的算术平方根是 2.82842…, 由于返回类型是整数,小数部分将被舍去。

class Solution {
    public int mySqrt(int x) {
        //二分查找的思路  
        //左边
        int left=0;
        //右边
        int right=x;
        //用来返回结果
        int index=0;
        //当左边小于右边的时候
        while(left<=right){
            //获取中间的那一个
            int mid=left+(right-left)/2;
            //中间的数平方 如果小于 从中间的左边算起 如果大于从中间右边算起
            if((long)mid*mid<=x){
                index=mid;
                left=mid+1;
            }else{
                right=mid-1;
            }
        }
        //返回下标
        return index;
    }
}

阶乘后的零

给定一个整数 n ,返回 n! 结果中尾随零的数量。

提示 n! = n * (n - 1) * (n - 2) * … * 3 * 2 * 1

 

示例 1:

输入:n = 3
输出:0
解释:3! = 6 ,不含尾随 0
示例 2:

输入:n = 5
输出:1
解释:5! = 120 ,有一个尾随 0
示例 3:

输入:n = 0
输出:0



class Solution {
    public int trailingZeroes(int n) {

        //其实就是算5的个数
             int zoreCount=0;
         while(n >= 5) {
            zoreCount += n / 5;
            n /= 5;
          }

        return zoreCount;
    
    
    }

 
}

K 进制表示下的各位数字总和

给你一个整数 n(10 进制)和一个基数 k ,请你将 n 从 10 进制表示转换为 k 进制表示,计算并返回转换后各位数字的 总和 。

转换后,各位数字应当视作是 10 进制数字,且它们的总和也应当按 10 进制表示返回。

 

示例 1:

输入:n = 34, k = 6
输出:9
解释:34 (10 进制) 在 6 进制下表示为 54 。5 + 4 = 9 。
示例 2:

输入:n = 10, k = 10
输出:1
解释:n 本身就是 10 进制。 1 + 0 = 1 。

class Solution {
    public int sumBase(int n, int k) {
        //搞一个结果
            int result=0;
            //当n不等于0的时候
            while(n!=0){
                //结果等于结果加上n 余上k进制
                result=result+(n%k);
                //这个数出于k
                n=n/k;
            }

            return result;
    }
}

用两个栈实现队列

用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )

 

示例 1:

输入:
[“CQueue”,”appendTail”,”deleteHead”,”deleteHead”]
[[],[3],[],[]]
输出:[null,null,3,-1]
示例 2:

输入:
[“CQueue”,”deleteHead”,”appendTail”,”appendTail”,”deleteHead”,”deleteHead”]
[[],[],[5],[2],[],[]]
输出:[null,-1,null,null,5,2]


class CQueue {
    //用两个栈来实现一个队列 就是先把栈的数据导出来 然后 弹出一个 然后在倒回去
      Stack<Integer> firstStack= new Stack<Integer>();
        Stack<Integer> secondStack= new Stack<Integer>();


    public CQueue() {

    }
    
    public void appendTail(int value) {
            firstStack.push(value);
    }
    
    public int deleteHead() {
        if(firstStack.isEmpty()){
            return -1;
        }
        while(!firstStack.isEmpty()){
            int value= firstStack.pop();
            secondStack.push(value);
        }
        int temp=secondStack.pop();
        while(!secondStack.isEmpty()){
            int value=secondStack.pop();
            firstStack.push(value);
        }
        return temp;
    }
}

/**
 * Your CQueue object will be instantiated and called as such:
 * CQueue obj = new CQueue();
 * obj.appendTail(value);
 * int param_2 = obj.deleteHead();
 */

斐波那契数列

写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下:

F(0) = 0,   F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。

答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

 

示例 1:

输入:n = 2
输出:1
示例 2:

输入:n = 5
输出:5

class Solution {
    public int fib(int n) {
        //用一个数组来进行递归添加
        if(n==0){
            return 0;
        }
        if(n==1){
            return 1;
        }
        int[] arr=new int[n+1];
        arr[0]=0;
        arr[1]=1;
        for(int i=2;i<=n;i++){
            arr[i]=(arr[i-1]+arr[i-2])%1000000007;
        }
        return arr[n];
    }
}

青蛙跳台阶问题

一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。

答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

示例 1:

输入:n = 2
输出:2
示例 2:

输入:n = 7
输出:21
示例 3:

输入:n = 0
输出:1


class Solution {
    public int numWays(int n) {
        //如果n小于等于1那么返回1
     if(n<=1){
            return 1;
        }
        //搞个数组加1
         int[] arr=new int[n+1];
         //数组  最终长度为 arr[i]=arr[i-1]+arr[i-2]
        arr[0]=1;
        arr[1]=2; 
         for(int i=2;i<n;i++){
             arr[i]=(arr[i-1]+arr[i-2])%1000000007;
         }

         return arr[n-1];
    }
}


二进制中1的个数
编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为 汉明重量).)。

提示:

请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。
在 Java 中,编译器使用 二进制补码 记法来表示有符号整数。因此,在上面的 示例 3 中,输入表示有符号整数 -3。

示例 1:

输入:n = 11 (控制台输入 00000000000000000000000000001011)
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 ‘1’。
示例 2:

输入:n = 128 (控制台输入 00000000000000000000000010000000)
输出:1
解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 ‘1’。
示例 3:

输入:n = 4294967293 (控制台输入 11111111111111111111111111111101,部分语言中 n = -3)
输出:31
解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 ‘1’。


public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        //这个就是拿1 进行不断的左移 然后匹配到了就加1
        int count=0;
       int flag=1;
       while(flag!=0){
           if((n&flag)!=0){
               count++;
           }
           flag<<=1;
       }
       return count;
    }
}

求平方根

给定一个非负整数 x ,计算并返回 x 的平方根,即实现 int sqrt(int x) 函数。

正数的平方根有两个,只输出其中的正数平方根。

如果平方根不是整数,输出只保留整数的部分,小数部分将被舍去。

 

示例 1:

输入: x = 4
输出: 2
示例 2:

输入: x = 8
输出: 2
解释: 8 的平方根是 2.82842…,由于小数部分将被舍去,所以返回 2

class Solution {
    public int mySqrt(int x) {
        //这个题用二分法然后接近结果
        int  left=0;
        int  right=x;
        int result=0;

        while(left<=right){
            int mid=(left+(right-left)/2);
                if((long)mid*mid<=x){
                    result=mid;
                    left=mid+1;
                }else{
                    right=mid-1;
                }
            
            }
        return result;
    }
}

栈的最小值

请设计一个栈,除了常规栈支持的pop与push函数以外,还支持min函数,该函数返回栈元素中的最小值。执行push、pop和min操作的时间复杂度必须为O(1)。

示例:

MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); –> 返回 -3.
minStack.pop();
minStack.top(); –> 返回 0.
minStack.getMin(); –> 返回 -2.

class MinStack {

    /** initialize your data structure here. */
    //搞两个栈 一个放最小值 一个放正常值  每次放正常值的时候会先把最小值拿出来 然后比较一下 一起同步塞一个最小值进去
    Stack<Integer> stack= new Stack<Integer>();
    Stack<Integer> minStack= new Stack<Integer>();

    public MinStack() {

    }
    
    public void push(int x) {
        stack.push(x);
        if(minStack.size()>0){
         int min=minStack.peek();
         min=Math.min(min,x);
         minStack.push(min);
        }else{
            minStack.push(x);
        }

    }
    
    public void pop() {
        stack.pop();
        minStack.pop();
    }
    
    public int top() {
        return stack.peek();   
    }
    
    public int getMin() {
       return minStack.peek(); 
    }
}

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(x);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.getMin();
 */


  TOC