学习Java

leetcode

    • 001两数之和
      • 代码(学习哈希)
    • 002两数相加
      • 代码(学习链表的创建和叠加)
    • 003无重复字符的最长子串
      • 代码(学习滑动窗口,暂时不会)
    • 004寻找两个正序数组的中位数
      • 代码
    • 005最长回文子串
      • 代码一(学习中心扩散法)
      • 代码二(学习动态规划,暂时不会)
    • 006 Z字形变换
      • 代码(找规律,周期性)
    • 007整数反转
      • 代码(公式)
    • 008字符串转换整数
      • 代码(公式)
    • 009回文数
      • 代码(Java底层函数)
    • 010正则表达式匹配
    • 代码(学习动态规划,暂时不会)
    • 011盛最多水的容器
      • 代码(双指针)
    • 012整数转罗马数字
      • 代码(暴力求解)
    • 013罗马数字转整数
      • 代码(找规律)
    • 014最长公共前缀
      • 代码(暴力求解)
    • 015三数之和
      • 代码(学习双指针)
    • 016最接近的三数之和
      • 代码(双指针)
    • 017电话号码的字母组合
      • 代码一(学习队列.暂时不会)
      • 代码二(学习递归,暂时不会)
    • 018四数之和
      • 代码(双指针)
    • 019删除链表的倒数第N个结点
      • 代码(链表)
    • 020有效的括号
      • 代码(栈)
    • 021合并两个有序链表
      • 代码(合并链表)
    • 022括号生成
      • 代码(学习队列,暂时不会)
    • 023合并K个升序链表
      • 代码
    • 024两两交换链表中的节点
      • 代码
    • 025K个一组链表翻转
      • 代码

001两数之和

代码(学习哈希)

class Solution {
    public int[] twoSum(int[] nums, int target) {
        /*
        题目重点:
        返回的是下标
        对应一个答案
        同一元素不能重复出现
         */
        //  创建动态哈希表,元素顺序存取顺序不能保持一致
        Map<Integer,Integer>map=new HashMap<Integer,Integer>();
        // 遍历数组
        for(int i=0;i<nums.length;i++){
            // 求差值
            int sub=target-nums[i];
            // 判断哈希表中的key值是否有该差值
            if(map.containsKey(sub)){
                // 如果有
                //map.get(Object key)根据键获取值
                //即根据元素获取下标
                return new int[] {i,map.get(sub) };
            }
            else{
                // 如果没有,则存入哈希表
                // key为元素
                // value为下标
                map.put(nums[i],i);
            }
        }
        return null;
    }
}
/*
V put(K key,V value):
将一个键值对存放到Map中,
如果关键字已存在,则用新值替换映射中原有的值
此代码中不用担心重复元素的原因:
遍历数组时,
先求差值,
判断哈希表中是否有该key值,
没有的时候才会存入,
故当targert是两相等元素之和
一个存入
一个还未存入
不用担心元素重复问题
*/

002两数相加

代码(学习链表的创建和叠加)

/**
 * 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) {
		/*
		 题目信息:
		 两个非空的链表
		 逆序存储
		 除了数字0不会以0开头
		 */
		/*
		 * 依次相加
		 * 注意考虑进位
		 */
//		创建头结点
		ListNode head=new ListNode();
//		指向head
		ListNode node=head;
//		依次将每个结点相加,记得考虑进位
//		初始化进位为0
		int so=0;
//		遍历两个链表叠加
//		直到两个链表均遍历完
		ListNode p=l1;
		ListNode q=l2;
		while(p!=null||q!=null) {
//			初始化进位、两个对应结点的和为进位大小
			int sum=so;
			if(p!=null) {
				sum+=p.val;
			}
			if(q!=null) {
				sum+=q.val;
			}
//			创建node的下一个结点,大小为sum%10;
			node.next=new ListNode(sum%10);
//			更新进位
			so=sum/10;
			/*
			 * 记得要考虑p、q结点是否为null
			 */
			if(p!=null) {
				p=p.next;
			}
			if(q!=null) {
				q=q.next;
			}
			node=node.next;
		}
//		叠加之后要考虑是否仍存在进位,是否需要创建新结点
		if(so==1) {
			node.next=new ListNode(so);
		}
		return head.next;
	}
}

003无重复字符的最长子串

代码(学习滑动窗口,暂时不会)


004寻找两个正序数组的中位数

代码

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        /*
        题目已知:
        两个正序的数组,从小到大
        题目要求:
        找出两个正序数组的中位数
        时间复杂度O(log(m+n))
        解放方法:
        先求两数组的长度之和
        判断数组奇偶
        然后遍历两数组,查找中间值
        */
        // length1记录数组num1的长度
        int length1=nums1.length;
        // length2记录数组num2的长度
        int length2=nums2.length;
        // 如果有两个数组长度均为0
        if(length1==0&&length2==0){
            return 0;
        }
        // 如果其中一个数组长度为0
        else if(length1==0||length2==0){
            // 如果nums1的长度为0
            if(length1==0){
                // 如果nums2的长度为偶数
                if(length2%2==0){
                    return (nums2[length2/2-1]+nums2[length2/2])/2.0;
                }
                 // 如果nums2的长度为奇数
                else{
                    return nums2[length2/2];
                }
            }
             // 如果nums2的长度为0
            else{
                // 如果nums1的长度为偶数
                if(length1%2==0){
                    return (nums1[length1/2-1]+nums1[length1/2])/2.0;
                }
                 // 如果nums1的长度为奇数
                else{
                    return nums1[length1/2];
                }
            }
        }
        // 两者长度均不为空
        else{
            // length记录数组的长度之和
            int length=length1+length2;
            // 如果长度之和为奇数
            if(length%2!=0){
                // 返回第几大的元素
                int mid=length/2+1;
                // 记录从小到大,第几个元素
                int order=0;
                // 遍历数组
                for(int i=0,j=0;i<length1||j<length2;){
                     // 如果其中一个已经遍历完
                    if(i>=length1||j>=length2){
                        // nums1遍历完
                        if(i>=length1){
                            if(order<mid){
                                return nums2[j-1+mid-order];
                            }
                        }
                        //nums2遍历完
                        else{
                           if(order<mid){
                                return nums1[i-1+mid-order];
                            }
                        }
                    }
                    // 两个数组均未遍历完
                    if(i<length1&&j<length2){
                        // 比较元素大小
                        // nums1的元素不大于nums2的元素
                        if(nums1[i]<=nums2[j]){
                            // 计数加一
                            order++;
                            // 判断order是否等于mid
                            if(order==mid){
                                return nums1[i];
                            }
                            // nums1下标加一
                            i++;
                        }
                        // nums2的元素较小
                        else{
                            // 计数加一
                            order++;
                            // 判断order是否等于mid
                            if(order==mid){
                                return nums2[j];
                            }
                            // nums2下标加一
                            j++;
                        }
                    }
                }
            }
            // 如果长度之和为偶数
            else{
                // 记录mid1,mid2记录中间两个数的排次
                int mid1=length/2;
                int mid2=length/2+1;
                // 记录从小到大,第几个元素
                int order=0;
                // 记录中间第一个数的大小
                int element1=0;
                // 遍历数组
                for(int i=0,j=0;i<length1||j<length2; ){
                    // 如果其中一个已经遍历完
                    if(i>=length1||j>=length2){
                        // nums1遍历完
                        if(i>=length1){
                        //表明一个还没找到
                            if(order<mid1){
                                return (nums2[j-1+mid1-order]+nums2[j-1+mid2-order])/2.0;
                            }
                            //表明已找到第一个
                            else{
                                return (element1+nums2[j])/2.0;
                            }
                        }
                        //nums2遍历完
                        else{
                           if(order<mid1){
                                return (nums1[i-1+mid1-order]+nums1[i-1+mid2-order])/2.0;
                            }
                            else{
                                return (element1+nums1[i])/2.0;
                            } 
                        }
                    }
                    // 如果两个数组均为遍历完
                    if(i<length1&&j<length2){
                        // 如果nums1的元素不大于nums2的元素
                        if(nums1[i]<=nums2[j]){
                            // 计数加一
                            order++;
                            // 如果为中间的两个数
                            if(order==mid1){
                                element1=nums1[i];
                            }
                            else if(order==mid2){
                                // 此时两个均找到
                                return (element1+nums1[i])/2.0;
                            }
                            // 遍历下一个
                            i++;
                        }
                        // 如果nums2的元素较小
                        else{
                            // 计数加一
                            order++;
                            // 如果为中间的两个数
                            if(order==mid1){
                                element1=nums2[j];
                            }
                            else if(order==mid2){
                                // 此时两个均找到
                                return (element1+nums2[j])/2.0;
                            }
                            // 遍历下一个
                            j++;
                        }
                    }
                }
            }
        }
        return 0;
    }
}
/*
写题中间遇到的错误点:
遍历数组时,结束条件用的||,i

005最长回文子串

代码一(学习中心扩散法)

class Solution {
    public String longestPalindrome(String s) {
        // 中心扩散法
        // 如果字符串的长度小于等于一
        if(s.length()<=1){
            return s;
        }
        else{
            int start=0,end=0;
            // 记录最长会问子串长度
            int maxLength=0;
            // 记录遍历中回文子串的长度
            int length=1;
            // 遍历字符串
            for(int i=0;i<s.length();i++){
                // 初始化
                int m=i-1,n=i+1;
                // 记录当前遍历的字符
                char ch=s.charAt(i);
                 // 首先往左遍历,相同则继续,否则结束。
                while(m>=0&&s.charAt(m)==ch){
                    // 左移
                    m--;
                    length++;
                }
                // 其次往右遍历,相同则继续,否则结束。
                while(n<s.length()&&s.charAt(n)==ch){
                    // 右移
                    n++;
                    length++;
                }
                // 最后左右同时遍历,相同则继续,否则结束
                while(m>=0&&n<s.length()&&s.charAt(m)==s.charAt(n)){
                    // 注意此时增加了两个元素
                    length+=2;
                    // 左移
                    m--;
                    // 右移
                    n++;
                }
                if(length>maxLength){
                    maxLength=length;
                    start=m+1;
                    end=n;
                }
                // 注意复原
                length=1;
            }
            // substring(start,end)截取字符串[start,end)
            return s.substring(start,end);
        }
    }
}

代码二(学习动态规划,暂时不会)


006 Z字形变换

代码(找规律,周期性)

class Solution {
    public String convert(String s, int numRows) {
        // 判断字符串的长度
        // 如果字符串的长度小于等于行数或者行数为一时
        if(s.length()<=numRows||numRows==1){
            return s;
        }
        // 将字符串转换为字符数组
        char[] arr=s.toCharArray();
        // 记录输出的字符串
        StringBuffer str=new StringBuffer();
        // 同行中,一个周期中的第二个字符与下一个周期中第一个字符的间距
        int other=0;
        // 记录周期数
        int distance=numRows+numRows-2;
        // 遍历行数
        for(int i=0;i<numRows;i++){
            // 经观察发现,每个周期,仅第一行和最后一行每个周期仅一个字符,其他有两个
            if(i!=0&&i!=distance){
                // 其他行中,一个周期中的第二个字符与下一个周期中的第一个字符的间距逐渐增加2
                other+=2;
            }
            // 遍历字符数组
            for(int j=i;j<s.length();){
                // 第一行和最后一行每个周期仅一个字符
                if(i==0||i==distance-1){
                    str.append(String.valueOf(arr[j]));
                    // 下一个字符的位置
                    j+=distance;
                }
                else{
                    // 其他行有两个
                    str.append(String.valueOf(arr[j]));
                    j+=distance;
                    // 注意要判断是否越界或重复计算前面已遍历的字符
                    if(j-other>j-distance&&j-other<s.length()){
                        str.append(String.valueOf(arr[j-other]));
                    }
                }
            }
        }
        return str.toString();
    }
}

007整数反转

代码(公式)

class Solution {
    public int reverse(int x) {
        int re=0;
        while(x!=0){
            /*
            为什么不用考虑相等的情况呢?
            以最大值为例子
            最大值为2147483647
            可见一个数经反转过程中符合
            re=Integer.MIN_VALUE/10
            ||
            re=Integer.MAX_VALUE/10
            不超过int范围的话
            初始最高位只能为0或者1
            故符合相等条件的反转数在int范围内
            */
            if(re<Integer.MIN_VALUE/10||re>Integer.MAX_VALUE/10){
                return 0;
            }
           	//公式
            re=re*10+x%10;
            x/=10;
        }
        return re;
    }
}

008字符串转换整数

代码(公式)

class Solution {
    public int myAtoi(String s) {
        // 去空格
        String str=s.trim();
        // 记录有效数字
        long re=0;
        // 判断是整数还是负数
        // true代表整数
        // false代表负数
        boolean flag=true;
        // 遍历字符串
        for(int i=0;i<str.length();i++){
            char ch=str.charAt(i);
            /*
             判断第一个字符是否为有效字符
            有效字符只有
            +,-,'0'~'9'
            */
            if(i==0){
                // 负数
                if(ch=='-'){
                    flag=false;
                }
                // 有效数字,默认为正数
                else if('0'<=ch&&ch<='9'){
                //公式
                    re=re*10+ch-'0';
                }
                // 非法字符串
                else if(ch!='+'){
                    break;
                }
            }
            // 有效数字
            else if('0'<=ch&&ch<='9'){
                re=re*10+ch-'0';
            }
            // 除第一位外的字符,非数字字符均是非法的
            else{
                break;
            }
            // 判断是否越界
            if(flag&&re>Integer.MAX_VALUE){
                return Integer.MAX_VALUE;
            }
            else if(!flag&&-re<Integer.MIN_VALUE){
                return Integer.MIN_VALUE;
            }
        }
        // 判断符号
        if(!flag){
            re=-re;
        }
        return (int)re;
    }
}

009回文数

代码(Java底层函数)

class Solution {
    public boolean isPalindrome(int x) {
        // 回文数,可以利用StringBuffer的reverse反转函数
        // 将n转换为StringBuffer类型
        StringBuffer s=new StringBuffer(String.valueOf(x));
        return s.reverse().toString().equals(String.valueOf(x));
        /*
        reverse方法实现字符串反转,StringBuffer有但是String没有
        String.valuOf方法实现转换为字符串类型功能
        toString将调用对象转换为字符串String类型
        equals用来比较两字符串是否相等
        */
    }
}

010正则表达式匹配

代码(学习动态规划,暂时不会)


011盛最多水的容器

代码(双指针)

class Solution {
    public int maxArea(int[] height) {
        // 记录最大面积
        int max=0;
        // 数组长度
        int length=height.length;
        // 初始较低高度
        int h=-1;
        // 遍历数组
        for(int i=0,j=length-1;i<j;){
            // 取较低的高度
            if(height[i]<=height[j]){
                // 随着i,j的移动,长度在缩小,所以较低高度需要比之前的大才用比较
                if(height[i]>h){
                    max=Math.max(max,height[i]*(j-i));
                    h=height[i];
                }
                i++;
            }
            else if(height[i]>height[j]){
                if(height[j]>h){
                   max=Math.max(max,height[j]*(j-i));
                   h=height[j];
                   
                }
                j--;
            }
        }
        return max;
    }
}

012整数转罗马数字

代码(暴力求解)

class Solution {
    public String intToRoman(int num) {
        StringBuffer str=new StringBuffer("");
        // 将会用到的罗马字符与对应的数字罗列出来
        String[] arr1={"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
        int[] arr2={1000,900,500,400,100,90,50,40,10,9,5,4,1};
        // 遍历数组
        for(int i=0;i<arr2.length&&num!=0; ){
            if(num>=arr2[i]){
                num-=arr2[i];
                str.append(arr1[i]);
            }
            else{
                i++;
            }
        }
        return str.toString();

    }
}

013罗马数字转整数

代码(找规律)

class Solution {
    public int romanToInt(String s) {
        /*
        题目重点:
        通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例
        */
        /*
        思路:
        通过变量num来记录整数
        逆序遍历字符串
        注意判断当前遍历的罗马数字是否比邻近的右边的罗马数字小
        如果比右边的小,则减
        否则加
        */
        // 记录整数
        int num=0;
        // 记录s的长度
        int length=s.length();
        // 求最后一个字符的罗马数字
        char rear=s.charAt(length-1);
        // 求最后一个字符的罗马数字对应的整数
        switch(rear){
                case 'I':
                    num=1;
                    break;
                case 'V':
                    num=5;
                    break;
                case 'X':
                    num=10;
                    break;
                case 'L':
                    num=50;
                    break; 
                case 'C':
                    num=100;
                    break;
                case 'D':
                    num=500;
                    break;
                case 'M':
                    num=1000;
                    break; 
        }
        // 字符串长度为1
        if(s.length()==1){
            return num;
        }
        // 字符串长度大于1
        else{
            // 记录当前遍历的罗马数字右边邻近的罗马数字对应的数字
            int index1=num;
            for(int i=length-2;i>=0;i--){
                // 记录当前遍历的罗马数字
                char front=s.charAt(i);
                // 记录当前罗马数字对应得数字
                int index2=0;
                // 求罗马数字对应的数字
                switch(front){
                case 'I':
                    index2=1;
                    break;
                case 'V':
                    index2=5;
                    break;
                case 'X':
                    index2=10;
                    break;
                case 'L':
                    index2=50;
                    break; 
                case 'C':
                    index2=100;
                    break;
                case 'D':
                    index2=500;
                    break;
                case 'M':
                    index2=1000;
                    break; 
                 }
                //  当前遍历的罗马数字小于右边邻近的数字时
                 if(index2<index1){
                    //  做减法
                     num-=index2;
                 }
                //  反之
                 else{
                    //  做加法
                     num+=index2;
                 }
                //  记录当前的罗马数字对应的数字
                 index1=index2;
            }
        }
        return num;
    }
}

014最长公共前缀

代码(暴力求解)

class Solution {
    public String longestCommonPrefix(String[] strs) {
        /*
        两个for循环
        第一个for循环:
        结束条件:第一个字符串中的长度或第二个for循环中遍历的字符不相等
        第二个for循环:
        结束条件:字符数组的长度或者遍历的字符不相等
        */
        int i=0,j=0;
        // 第一个for循环:
        // 遍历第一个字符串的字符
        for( ;i<strs[0].length();i++){
            // 记录当前遍历的字符
            char s=strs[0].charAt(i);
            // 第二个for循环:
            // 比较与第一个字符串相同下标的字符字符是否相同
            for(j=1;j<strs.length;j++){
                // 注意:容易犯错
                // 防止越界:因为不确定哪个字符串的长度最小
                if(i<strs[j].length()){
                    // 记录当前字符串的下标的字符
                    char ch=strs[j].charAt(i);
                    // 判断字符是否相同
                    if(ch!=s){
                        // 不相同结束
                        break;
                    }  
                }
                // 越界了
                else{
                    break;
                }
            }
            // 判断是否是两字符不相同结束
            if(j<strs.length){
                break;
            }
        }
        // 判断是否存在相同的前缀
        if(i>0){
            // 存在
            return strs[0].substring(0,i);
        }else{
            // 不存在
            return "";
        }
    }
}

015三数之和

代码(学习双指针)

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        if(nums.length<3){
            return new ArrayList<>();
        }
        else{
            // 排序,从小到达
            Arrays.sort(nums);
            if(nums[0]>0){
                return new ArrayList<>();
            }
            // 创建整数链表的链表
            List<List<Integer>> lists=new ArrayList<List<Integer>>();
            // 遍历数组
            for(int i=0;i<nums.length-2;i++){
                if(i==0||i>0&&nums[i]!=nums[i-1]){
                    // 双指针
                    int p=i+1,q=nums.length-1;
                    // 求两数之和,亦为差值
                    int sum=0-nums[i];
                    // 寻找两数之和为sum的两个数
                    while(p<q){
                        // 相等
                        if(nums[p]+nums[q]==sum){
                            // Arrays.asList()用于将数组转换为list
                            lists.add(Arrays.asList(nums[i],nums[p],nums[q]));
                            // 去重
                            while(p<q&&nums[p+1]==nums[p]){
                                p++;
                            }
                            while(p<q&&nums[q-1]==nums[q]){
                                q--;
                            }
                            p++;
                            q--;
                        }
                        // 小于则右移
                        else if(nums[p]+nums[q]<sum){
                            p++;
                        }
                        // 大于则左移
                        else{
                            q--;
                        }

                    }
                }
            }
            return lists;
        }
    }
}

016最接近的三数之和

代码(双指针)

class Solution {
    public int threeSumClosest(int[] nums, int target) {
        // 可以转换为求三个数之和的问题
        // 排序
        Arrays.sort(nums);
        // 记录最接近的和
        int sums=0;
        // 记录与target的距离
        int ans=Integer.MAX_VALUE;
        // 遍历数组
        for(int i=0;i<nums.length-2;i++){
            // 双指针
            int p=i+1,q=nums.length-1;
            // 转换为求两数之和
            int sum=target-nums[i];
            while(p<q){
                // 三个数之和为target
                if(nums[p]+nums[q]==sum){
                    return target;
                }
                // 较小,右移
                else if(nums[p]+nums[q]<sum){
                    int t=sum-nums[p]-nums[q];
                    // 比较离target的距离
                    if(Math.abs(t)<Math.abs(ans)){
                        // 更新
                        ans=t;
                        // 更新三个整数之和
                        sums=nums[i]+nums[p]+nums[q];
                    }
                    p++;
                }
                else{
                    int t=sum-nums[p]-nums[q];
                    if(Math.abs(t)<Math.abs(ans)){
                        ans=t;
                        sums=nums[i]+nums[p]+nums[q];
                    }
                    q--;
                }
            }
        }
        return sums;
    }
}

017电话号码的字母组合

代码一(学习队列.暂时不会)

代码二(学习递归,暂时不会)

018四数之和

代码(双指针)

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        if(nums.length<4){
            return new ArrayList<>();
        }
        // 创建链表
        List<List<Integer>> list=new ArrayList<>();
        // 排序
        Arrays.sort(nums);
        // if(nums[0]+nums[1]+nums[3]>target){
            /*
            不能这样判断(忘记考虑负数的情况),比如
            [0,-5,5,1,1,2,-5,5,-3]
            -11
            */
        //     /*
        //     不能带等号,比如
        //     [0,0,0,0]
        //     0
        //     */
        //     return list;
        // }
        // 遍历数组
        // 第一个数
        for(int i=0;i<nums.length-3;i++){
            // 防止重复
            if (i==0||(i>0&&nums[i]!=nums[i-1])){
                // 第二个数
                for(int j=i+1;j<nums.length-2;j++){
                    // 防止重复
                    if (j==i+1||nums[j-1]!=nums[j]) {
                        // 双指针
                        int p=j+1,q=nums.length-1;
                        // 转为求两数之和
                        int sum=target-nums[i]-nums[j];
                        while(p<q){
                            // 相等
                            if(nums[p]+nums[q]==sum){
                                list.add(Arrays.asList(nums[i],nums[j],nums[p],nums[q]));
                                // 防止重复
                                while(p<q&&nums[p]==nums[p+1]){
                                    p++;
                                }
                                while(nums[q]==nums[q-1]&&p<q){
                                    q--;
                                }
                                p++;
                                q--;
                            }
                            // 较小,右移
                            else if(nums[p]+nums[q]<sum){
                                p++;
                            }
                            // 较大,左移
                            else{
                                q--;
                            }
                        }
                    }
                }
            }
        }
        return list;
    }
}

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

代码(链表)

/**
 * 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) {
        // 倒数转换为整数
        // 先计算链表长度
        ListNode p=head,q=head;
        // 记录链表长度
        int size=0;
        // 求链表长度
        while(p!=null){
            size++;
            p=p.next;
        }
        // 除去第一个结点的时候
        /*
        易错点:
        下面的
        int t=size-n
        t代表的是要删除的结点前面有几个结点,
        而该链表head没有头结点
        故前面有0个结点
        要单独拿出来讨论
        */
        if(size==n){
            ListNode head1=new ListNode();
            ListNode node=head1;
            node.next=head.next;
            return head1.next;
        }
        // 记录删除结点的前一个结点的正数位置
        int t=size-n;
        int i=1;
        // 找要删除的结点的前一个结点
        while(i!=t){
            q=q.next;
            i++;
        }
        // 删除结点
        q.next=q.next.next;
        return head;
    }
}

020有效的括号

代码(栈)

class Solution {
    public boolean isValid(String s) {
        //    考察知识点:栈
        // 先判断字符串的长度,奇数一定不是有效的
        // 记录字符串的长度
        int length=s.length();
        // 判断是否为奇数
        if(length%2!=0){
            // 奇数
            return false;
        }
        else{
            // 偶数
            // 创建栈
            // 注意要用包装类Character
            Stack<Character>stack=new Stack<Character>();
            // 遍历字符串
            for(int i=0;i<length;i++){
                // 记录当前遍历的字符串
                char ch=s.charAt(i);
                // 如果是(、{、[则入栈
                if(ch=='('||ch=='{'||ch=='['){
                    // 入栈push()
                    stack.push(ch);
                }
                // 如果不是,则要取栈顶字符判断
                else{
                    /*
                        易忘记考虑情况一:
                        }[]
                    */
                    // 如果为空栈
                    if(stack.size()==0){
                        return false;
                    }
                    // 不是空栈,判断字符是否相同
                    else if(stack.size()!=0){
                        // 取栈顶字符pop()
                        char t=stack.pop();
                        // 判断是否是[],{},()对应
                        if(t=='('&&ch!=')'||t=='['&&ch!=']'||t=='{'&&ch!='}'){
                            // 不是
                            return false;
                        }
                        else{
                            // 是则继续遍历
                            continue;
                        }
                    }
                }
            }
            /*
            易忘记考虑情况地方二:
            ")}"
            */
            // 判断是否为空栈
            if(stack.size()!=0){
                // 不是空栈
                return false;
            }else{
                // 是空栈
                return true;
            }
        }
        
    }
}

021合并两个有序链表

代码(合并链表)

/**
 * 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) {
        // 链表list1为空
        if(list1==null&&list2!=null){
            return list2;
        }
        // 链表list2为空
        else if(list1!=null&&list2==null){
            return list1;
        }
        // 两个链表都为空
        else if(list1==null&&list2==null){
            return null;
        }
        // 两个链表都不为空
        else{
            // 创建头结点
            ListNode head=new ListNode();
            ListNode node=head;
            // 遍历链表list1,list2
            while(list1!=null&&list2!=null){
                // 当前遍历list1的结点的val较小或者两者相等
                if(list1.val<=list2.val){
                    node.next=list1;
                    list1=list1.next;
                    node=node.next;
                }
                else{
                    node.next=list2;
                    list2=list2.next;
                    node=node.next;
                }
            }
            // 当list1未遍历完
            if(list1!=null){
                node.next=list1;
            }
            // 当list2未遍历完
            else if(list2!=null){
                node.next=list2;
            }
            return head.next;
        }

    }
}

022括号生成

代码(学习队列,暂时不会)

023合并K个升序链表

代码

/**
 * 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) {
        // 将结点的val值存入数组中
        List<Integer> list=new ArrayList<>();
        for(ListNode node:lists){
            while(node!=null){
                list.add(node.val);
                node=node.next;
            }
        }
        //数组排序
        Collections.sort(list);
        // 创建链表
        ListNode list1=new ListNode();
        ListNode node=list1;
        for(int val:list){
            node.next=new ListNode(val);
            node=node.next;
        }
        return list1.next;
    }
}

024两两交换链表中的节点

代码

/**
 * 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 swapPairs(ListNode head) {
        // 判断是否为空
        if(head==null){
            return null;
        }
        // 用于记录当前遍历的结点的位次,结点总数
        int size=0;
        ListNode p=head;
        // 记录相邻结点翻转后的链表
        ListNode list=new ListNode();
        ListNode node=list;
        while(p!=null){
            // 结点的个数++
            size++;
            // 目的:记录第偶数个结点
            ListNode q=p;
            p=p.next;
            // 表明是第偶数个
            if(size%2==0){
                node.next=q;
                node=node.next;
                node.next=head;
                /*
                head.next=null不可漏掉,不然会陷入循环
                比如1 2 3 4
                list为头结点->2->1->4->3此时按道理说遍历完结束了
                但实际为
                list为头结点->2->1->4->3->4->3->4->3。。。。4,3一直循环,这是 因为原链表3指向4,但是我们没有改变
                */
                head.next=null;
                node=node.next;
                head=p;
            }
            
        }
        // 判断是否结点数是否为奇数,若为奇数,则有一个不用翻转,未添加
        if(size%2!=0){
            node.next=head;
            head.next=null;
        }
        return list.next;
    }
}

025K个一组链表翻转

代码

/**
 * 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 reverseKGroup(ListNode head, int k) {
        ListNode head1=head;
        // 记录结点个数
        int size=0;
        // 求结点个数
        while(head1!=null){
            size++;
            head1=head1.next;
        }
        // 将结点val值存入数组
        int[] arr=new int [size];
        int i=0;
        while(head!=null){
            arr[i++]=head.val;
            head=head.next;
        }
        // 记录循环的周期数
        int circles=size/k;
        // 记录翻转的链表
        ListNode newHead=new ListNode();
        ListNode node=newHead;
        int p=1;
        int q=k;
        int size1=0;
        while(p<=circles){
            while(q>(p-1)*k){
                node.next=new ListNode(arr[q-1]);
                size1++;
                node=node.next;
                q--;
            }
            p++;
            q=p*k;
        }
        // 检查是否有周期以外未遍历的结点
        while(size1<arr.length){
            node.next=new ListNode(arr[size1]);
            node=node.next;
            size1++;
        }
        return newHead.next;
    }
}

你可能感兴趣的:(java,leetcode,散列表)