leetcode1

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]
 

提示:

2 <= nums.length <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109
只会存在一个有效答案
进阶:你可以想出一个时间复杂度小于 O(n2) 的算法吗?

1.暴力解法:

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

 2.双向奔赴,减少遍历重复

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

3.使用哈希表降低时间复杂度

class Solution {
    public int[] twoSum(int[] nums, int target) {
       Map<Integer, Integer> hashMap = new HashMap<Integer, Integer>();
        for (int i = 0; i < nums.length; i++) {
            if (hashMap.containsKey(target - nums[i])) {
                return new int[]{hashMap.get(target - nums[i]), i};
            } else {
                hashMap.put(nums[i], i);//最初的哈希表实际上是空的,一个一个写,直到i是最后一个数字的索引,所以返回时把i写后面。
            }
        }
        return new int[0];//防止报错
    }
}

1.Integer是必要的,否则会报错,建议使用多态机制;

2.注意对int数组填值使用int[] {a,b}; 

3.注意最后为防止报错返回一个空,可以减少内存和时间消耗。

2.给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

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

示例 1:


输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.
示例 2:

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

输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出:[8,9,9,9,0,0,0,1]
 

提示:

每个链表中的节点数在范围 [1, 100] 内
0 <= Node.val <= 9
题目数据保证列表表示的数字不含前导零

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        //初始化结果链表,结果链表的尾节点,进位
        ListNode result=new ListNode(0);
        ListNode resulttail=result;//重点:用于指向当前节点
        int carry=0;
        //两个链表都结束了就可以直接返回result了
        while(l1!=null ||l2!=null){
            //n1存储l1当前节点的值,如果l1结束了,就是0
            int n1=l1==null?0:l1.val;
            int n2=l2==null?0:l2.val;
            int sum=n1+n2+carry;
            //在result链表中添加尾节点存储计算结果
            resulttail.next=new ListNode(sum%10);
            resulttail=resulttail.next;
            carry=sum/10;
            //移到下一个节点
            if(l1!=null){
                l1=l1.next;
            }
            if(l2!=null){
                l2=l2.next;
            }
        }
        //如果最后一位运算有进位,需要添加尾节点
        if(carry==1){
            resulttail.next=new ListNode(1);
        }
        return result.next;//首节点不能要,是直接初始出来的0
    }
}

主要是一开始根本没看懂尾节点和结果链表的关系,不清楚ListNode resulttail=result;的作用就是让尾节点指向链表的当前节点。需要注意:最后的返回值不能直接用result。

注意:1.返回的是一个链表,新建链表和指向链表的当前节点。

2.?:

2.26

听了mysql的课,做了几个数据库的题。

2.27

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

回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

例如,121 是回文,而 123 不是。
 

示例 1:

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

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

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

提示:

-231 <= x <= 231 - 1

class Solution {
    public boolean isPalindrome(int x) {
        if(x==0){return true;}
        if(x<0||x%10==0){return false;}//不为0且个位数为0的肯定不是回文数。
        //应注意:int类型的范围为-2147483648~2147483647,故整体inverse有可能会超出int范围。
        //只转换一半
        int inverseNumber=0;
        while(x>inverseNumber){
            inverseNumber=x%10+inverseNumber*10;
            x/=10;
        }
        //偶数位数字会相等,奇数位转换后的数字会是x的十倍。
        return (x==inverseNumber||x==inverseNumber/10);
    }
}

 注意点:1.不为0且个位数为0的数一定不是回文数;2.偶数位和奇数位的区别。3.转换一半以防结果溢出int类型。(初始化为long进行全转?)

206.给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
 

示例 1:


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


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

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

提示:

链表中节点的数目范围是 [0, 5000]
-5000 <= Node.val <= 5000
 

进阶:链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?

class Solution {
    public ListNode reverseList(ListNode head) {
        if(head==null){return null;}
        //让链表反向,就是让所有结点的next指向当前节点的前一个节点
        ListNode currentNode=head;//当前节点为头节点
        ListNode temp=null;//交换过程中存储原来的下一个节点位置
        ListNode frontNode=null;//当前节点的前一个节点
        while(currentNode!=null){
            temp=currentNode.next;
            currentNode.next=frontNode;
            frontNode=currentNode;
            currentNode=temp;
        }
        return frontNode;
    }
}

 主要就是修改每个节点里next的指向,所以需要中间值保存真正的next指向,方便当前节点移动到下一个节点。

另一种思路:

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

说明:

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

示例 1:

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

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

数组里所有数一起异或,结果就是唯一不同的数。 

class Solution {
    public int singleNumber(int[] nums) {
        int result=nums[0];
        for(int i=1;i<nums.length;i++){
            result=result^nums[i];
        }
        return result;
    }
}

3.5最近在学数据结构与算法,刷两个链表的题。

给你一个链表,删除链表的倒数第 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]
 

提示:

链表中结点的数目为 sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz
 

进阶:你能尝试使用一趟扫描实现吗?

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        //获取链表的长度
        int sum=1;
        ListNode temp=head.next;
        while(temp!=null){
            sum++;
            temp=temp.next;
        }
        //如果n>sum,返回null
        if(n>sum){
            return null;
        }
    
        ListNode front=head;
        if(n==1){
            //如果删除的是最后一个,不存在倒数第二个就返回null,否则让倒数第二个指向null
            if(sum==1){return null;}
            while(front.next.next!=null){
                front=front.next;
            }
            front.next=null;
            return head;
        }
        //如果删除的是头结点
        if(sum==n){
            return head.next;
        }
        //如果删除的不是尾节点
        for(int i=0;i<sum-n-1;i++){
            front=front.next;
        }
        front.next=front.next.next;//删除节点
        return head;
    }
}

过于复杂了,给链表加一个0头,可以省去三种情况的考虑。

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        //获取链表的长度
        int sum=0;
        ListNode result=new ListNode(0,head);
        ListNode temp=result;
        while(temp.next!=null){
            sum++;
            temp=temp.next;
        }
        ListNode front=result;
        for(int i=0;i<sum-n;i++){
            front=front.next;
        }
        front.next=front.next.next;
        return result.next;
    }
}

题目很适合压栈,然后删除弹出的第n个节点。

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode result=new ListNode(0,head);
        Stack<ListNode> stack=new Stack<>();
        ListNode temp=result;
        //全部压入
        while(temp!=null){
            stack.push(temp);
            temp=temp.next;
        }
        for(int i=0;i<n;i++){
            stack.pop();
        }
        stack.peek().next=stack.peek().next.next;
        return result.next;
    }
}

遍历了两遍,考虑只遍历一遍的方法,双指针?

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode result=new ListNode(0,head);
        ListNode tail=result;
        ListNode dst=result;
        for(int i=0;i<n;i++){
            tail=tail.next;
        }
        while(tail.next!=null){
            tail=tail.next;
            dst=dst.next;
        }
        //此时目标落在要删除的节点的前一个节点
        dst.next=dst.next.next;
        return result.next;
    }
}

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

示例 1:


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

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

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

提示:

两个链表的节点数目范围是 [0, 50]
-100 <= Node.val <= 100
l1 和 l2 均按 非递减顺序 排列

直接用的迭代:

class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        if(list1==null){return list2;}
        if(list2==null){return list1;}
        ListNode result=new ListNode(-101);
        ListNode r=result;
        ListNode temp1=list1;
        ListNode temp2=list2;
        while(true){
            if(temp1!=null&temp2!=null){
                if(temp1.val<=temp2.val){
                    r.next=temp1;
                    temp1=temp1.next;
                    r=r.next;
                }else{
                    r.next=temp2;
                    temp2=temp2.next;
                    r=r.next;
                }
            }
            if(temp1==null){
                r.next=temp2;
                break;
            }
            if(temp2==null){
                r.next=temp1;
                break;
            }
        }
        return result.next;
    }
}

考虑递归做法?还不太熟练递归思想。

class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        if(list1==null){
            return list2;
        }else if(list2==null){
            return list1;
        }else if(list1.val<list2.val){
            list1.next=mergeTwoLists(list1.next,list2);
            return list1;
        }else{
            list2.next=mergeTwoLists(list1,list2.next);
            return list2;
        }
    }
}

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

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

示例 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 = [[]]
输出:[]
 

提示:

k == lists.length
0 <= k <= 10^4
0 <= lists[i].length <= 500
-10^4 <= lists[i][j] <= 10^4
lists[i] 按 升序 排列
lists[i].length 的总和不超过 10^4

第一反应是递归,但是code出了点问题。 递归之递归了,目前只会这一种方法。

class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        ListNode res=null;
        Merge merge=new Merge();
        for(ListNode list:lists){
            res=merge.mergeList(list,res);
        }
        return res;
    }
}
class Merge{
    //排序两个链表
    public ListNode mergeList(ListNode list1,ListNode list2){
        if(list1==null){
            return list2;
        }else if(list2==null){
            return list1;
        }else if(list1.val<=list2.val){
            list1.next=mergeList(list1.next,list2);
            return list1;
        }else{
            list2.next=mergeList(list1,list2.next);
            return list2;
        }
    }
}

第一次做出困难题!!!

 141.给你一个链表的头节点 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
解释:链表中没有环。
 

提示:

链表中节点的数目范围是 [0, 104]
-105 <= Node.val <= 105
pos 为 -1 或者链表中的一个 有效索引 。

考虑哈希表,每经过一个节点就存到哈希表中,遍历链表时检查哈希表中是否存在当前节点,若存在返回true,否则返回false。

public class Solution {
    public boolean hasCycle(ListNode head) {
        boolean flag=false;
        int i=0;
        ListNode temp=head;
        Map<Integer,ListNode> hashMap=new HashMap<Integer,ListNode>();
        while(temp!=null){
            if(hashMap.containsValue(temp)){
                flag=true;
                break;
            }
            hashMap.put(i,temp);
            temp=temp.next;
            i++;
        }
        return flag;
    }
}

 其次,学习了一下快慢指针,只要快指针能追上慢指针,则说明有环。

public class Solution {
    public boolean hasCycle(ListNode head) {
        boolean flag=true;
        if(head==null || head.next==null){
            return false;
        }
        ListNode quick=head.next;
        ListNode slow=head;
        while(quick!=slow){
            if(quick==null || quick.next==null){
                return false;
            }
            quick=quick.next.next;
            slow=slow.next;
        }
        //要保证快指针不会空指针异常!
        return flag;
    }
}

注意:一开始让quick先跑是怕后面直接不进while循环!!!

142.给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 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
解释:链表中没有环。
 

提示:

链表中节点的数目范围在范围 [0, 104] 内
-105 <= Node.val <= 105
pos 的值为 -1 或者链表中的一个有效索引

 第一反应是哈希表!

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode temp=head;
        ListNode result=null;
        int i=0;
        Map<Integer,ListNode> hashMap=new HashMap<Integer,ListNode>();
        while(temp!=null){
            if(hashMap.containsValue(temp)){
                result=temp;
                break;
            }
            hashMap.put(i,temp);
            i++;
            temp=temp.next;
        }
        return result;
    }
}

可以使用快慢指针,降低时间复杂度。(需要重做)。

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode quick=head;
        ListNode slow=head;
        ListNode result=head;
        if(head==null){return null;}
        while(quick!=null){
            slow=slow.next;
            if(quick.next!=null){
                quick=quick.next.next;
            }else{
                return null;
            }
            if(quick==slow){
                while(result!=slow){
                    slow=slow.next;
                    result=result.next;
                }
                return result;
            }
        }
        return null;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值