20190918练习题总结——编程题

  1. (力扣2)给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。您可以假设除了数字 0 之外,这两个数都不会以 0 开头。

    示例:

    输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
    输出:7 -> 0 -> 8
    原因:342 + 465 = 807

  • 思路解析:我们在力扣网上可以看出人家给的方法传的是结点,再看看题目说是逆序,所以需要创建一个新的表,那么这个头结点采用虚拟头结点还是真实头结点呢?我们来分析一下,如果采用的是真实头结点,第一个结点创建地时候我们就要进行l1和l2相加,把和放进去,但是如果我们采用虚拟头结点地话,我们第一个结点不让元素,新进来地结点元素(和)往后插入就行,那么问题又来了?我们采用头插法还是尾插法?当然我们在这个问题中采用尾插法,因为人家要求逆序,所以我们还需要记录尾指针,如果l1和l2相加有进位我们还得存储进位的值,关于是否进位我们采用对10取余,将余数放入对于的位置

public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
		ListNode head=new ListNode(0); //虚拟头结点
		ListNode rear=head; //尾指针
		int carry=0;  //进位
		while(true){
			if(l1==null&&l2==null&&carry==0){
				break;
			}
			int num=(l1==null?0:l1.val)+(l2==null?0:l2.val)+carry;
			ListNode n=new ListNode(num%10);
			rear.next=n;
			rear=n;
			carry=num/10;
			
			l1=l1==null?null:l1.next;
			l2=l2==null?null:l2.next;
		}
		return head.next;
	}

2.(力扣19)给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。

示例:

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

当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:

给定的 n 保证是有效的。

  • 思路解析:看到这道题的直观想法可能就是,把倒数转换成正数,所以需要先遍历一遍表,遍历完了之后表的长度就知道了,长度-n+1就是正着数的位置,然后删除就可以了,但是能不能有个方法只用遍历一遍?我们可以考虑双指针,正着数和倒着数是不是有个差值,我们可以让一个指针先走,后一个指针后走,从而实现依次遍历就使得删除元素,并遍历出来白哦的元素,例如我们题中给的示例1->2->3->4->5,要删除倒数第二个元素,所以我们定义两个指针,一个先走两次,另一个指针和先走的这个指针一起走,直到先走的指针指向最后一个元素,那么后走的指针的下一个元素就是要删除的元素

public ListNode removeNthFromEnd(ListNode head, int n) {
        if(head==null||head.next==null){
        	return null;
        }
        ListNode r=head;
        ListNode l=head;
        for(int i=0;i<n;i++){
        	r=r.next;
        }
        if(r==null){
        	return head.next;
        }
        while(r.next!=null){
        	r=r.next;
        	l=l.next;
        }
        l.next=l.next.next;
        return head;
    }

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

示例:

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

  • 解题思路:这道题和之前我们所写的合并两个有序数组的题很相似,如果还没做过合并两个有序数组的小可爱们(感兴趣的话可以点击链接https://blog.csdn.net/qq_44941119/article/details/101000474看一看我之前写的这道题的解题思路,有个大概的了解),思路和它完全一样,这里我就不做过多的分析了,在此大家要注意一个穿针引线的概念。
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode head=new ListNode(0);
        ListNode p=head;
        ListNode p1=l1;
        ListNode p2=l2;
        while(true){
        	if(p1==null&&p2==null){
        		break;
        	}
        	if(p1!=null&&p2==null){
        		p.next=p1;
        		break;
        	}else if(p1==null&&p2!=null){
        		p.next=p2;
        		break;
        	}else if(p1.val<=p2.val){
        		p.next=p1;
        		p1=p1.next;
        	}else{
        		p.next=p2;
        		p2=p2.next;
        	}
        	p=p.next;
        }
        return head.next;
    }

4.(力扣328)给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。

请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。

示例 1:

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

输入: 2->1->3->5->6->4->7->NULL 
输出: 2->3->6->7->1->5->4->NULL
说明:

应当保持奇数节点和偶数节点的相对顺序。
链表的第一个节点视为奇数节点,第二个节点视为偶数节点,以此类推。

  • 思路解析:看到题目中的节点编号的奇偶性,而不是节点的值的奇偶性,原地算法也就是不能取创建新的链表,空间复杂度应为 O(1)则表明避免我们遍历链表,一个for循环就可以了,同样这个题我们可以采用穿针引线的方法来解决,将奇数串在一起,偶数串在一起,但是因为我们要先奇后偶,也就是说最后一个奇数的下一跳是指向偶数的第一个,所以我们需要记录偶数第一个位置,我们定义两个指针一个指向奇数一个指向偶数,两个指针同时走,但是当数字总个数是奇数的时候,偶先出去,因为偶在奇的前面,偶=null,当数字总数是偶数个的时候,最后的结果是偶的下一跳是null。因为要奇数后面串偶数,所以奇最终不能为null;

public ListNode oddEvenList(ListNode head) {
        if(head==null||head.next==null){
            return head;
        }
        ListNode ji=head;
        ListNode ou=head.next;
        ListNode ouStart=ou;
        while(true){
            if(ou==null||ou.next==null){
                break;
            }
            ji.next=ji.next.next;
            ou.next=ou.next.next;
            ji=ji.next;
            ou=ou.next;
        }
        ji.next=ouStart;
        return head;
    }

5.(力扣141)给定一个链表,判断链表中是否有环。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

示例 1:

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


示例 2:

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


示例 3:

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

  • 思路解析:题中的pos表示的是位置,我们首先要想到的实在怎样取判断是否有环,比如两个人跑步,一个跑的快一个跑的慢,总有那么一个瞬间跑的快的追上了跑的慢的,这时候不就形成了一个环,这里的两个人就相当于两个指针,所以就引出了快慢指针的概念,fast和slow,两个指针都从头开始,一个快一个慢,两个指针同时走,当fast追上low的时候就是有环,那么什么时候没有环就是fast先为null的时候
       public boolean hasCycle(ListNode head) {
            if(head==null||head.next==null){//判断为空
            	return false;
            }
            ListNode fast=head; //快指针
            ListNode slow=head; //慢指针
            while(true){
            	if(fast==null||fast.next==null){
            		return false;
            	}
            	slow=slow.next;
            	fast=fast.next.next;
            	if(slow==fast){
            		return true;
            	}
            }
        }

    6.(力扣142)给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

    为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

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

    示例 1:

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


    示例 2:

    输入:head = [1,2], pos = 0
    输出:tail connects to node index 0
    解释:链表中有一个环,其尾部连接到第一个节点。


    示例 3:

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

  • 思路解析:这也是一个环的问题,但是和上一个题不一样的地方是在让你找出环的位置,和上一道题一样采用快慢指针来解决,要找到出环的位置,也就是slow==fast,但是如果fast和slow走的步数一样就不是环,所以要判断出环首先fast==slow,但是前提是两个指针走的步数要不一样,所以我们可以让fast一直往后走,但是slow在fast没走一步后都要从头开始走,这样他们就会有步数不一样但是能够相遇的点,那个相遇的点就是环的位置,所以还需要定义一个变量来统计fast走的步数。

public ListNode detectCycle(ListNode head) {
        if(head==null||head.next==null){ //判断为空,然后null 
        	return null;
        }
        ListNode fast=head; //快指针
        ListNode slow=head; //慢指针
        int step=0; //记录fast走的步数
        while(fast!=null){
        	fast=fast.next;//fsat一直往后走
        	step++; //步数++
        	slow=head; //slow始终从头开始
        	for(int i=1;i<=step;i++){ //fsat没走一步,slow要从头开始
        		if(slow==fast&&step!=i){
        			return slow;
        		}
        		slow=slow.next;
        	}
        }
        return null;//跳出循环返回null
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值