为了转行程序员而努力的第二十九天-链表,抽象类,封装,接口

还是提前醒了,已经很久没有真正睡过一个好觉了,昨天花了很多时间去说服父母,还是渴望得到理解吧,哪怕只是不再被否定自己的想法,再被灌输他们的观念,以至于没有时间写总结。决定自己留在工作的城市过春节,有更多的时间思考,而不是像以前一样很容易就被别人影响了。

但其实以前成天有人想要告诉你该怎么怎么做,突然一下真的放手让你自己做决定了,又开始有点犹豫了,这就是被管束太久,所以逐渐失去了独立决策,以及面对自己选择的后果的能力了吧,越是大的事情,越想要去找别人分担决策的风险,但其实,自己的人生选择,不管有多少人参与了决策的过程,有多少人用自己的观念来影响你,最终不得不承受结果的,还是只有自己而已,其实勇敢面对自己的决策失误也是一件需要克服的事情吧,就像是刷题和演讲一样。

最近几天一直在刷链表,已经快要自闭了,几乎每一道题,但凡是自己思考的,都陷入了逻辑陷阱里,一串又一串的选择循环判断,最后还过不了测试案例,参考了别人的答案,倒是能够复写一遍,但是这样下去真的只能把每一种题型都背一个模版了吗,这一块后期是肯定会复刷的,不然面试的时候如果遇到了很容易卡住,希望不停的练习能够熟悉起来找到方法吧。

今日进度:
1.其实是昨天的进度,终于敢于把自己的想法和努力直白地有自信地和父母分享了,才发现有的事情真的是我觉得理所当然的,其实他们并不知道,在科普的同时,也更能互相理解了
2.决定坚持自己选择的方向,哪怕这条道路上充满了艰辛,也是自己选择的
3.坚持录小王子,其实等小王子录完之后,想尝试一下英文短文
4.坚持锻炼,继续做之前看好的适合久坐不动的人做的十几分钟肩颈活动
5.坚持记录

学习笔记:
1.如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。
2.如果你想设计这样一个类,该类包含一个特别的成员方法,该方法的具体实现由它的子类确定,那么你可以在父类中声明该方法为抽象方法。抽象方法没有定义,方法名后面直接跟一个分号,而不是花括号。

public abstract double computePay();

3.声明抽象方法会造成以下两个结果:
如果一个类包含抽象方法,那么该类必须是抽象类。
任何子类必须重写父类的抽象方法,或者声明自身为抽象类。
4.在面向对象程式设计方法中,封装(英语:Encapsulation)是指,一种将抽象性函式接口的实作细节部份包装、隐藏起来的方法。任何要访问类中私有成员变量的类都要通过这些getter和setter方法。
5.接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。
6.接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。
7.接口与类的区别:
接口不能用于实例化对象。
接口没有构造方法。
接口中所有的方法必须是抽象方法。
接口不能包含成员变量,除了static和final变量。
接口不是被类继承了,而是要被类实现。
接口支持多重继承。

/* 文件名 : NameOfInterface.java */ 
import java.lang.*; //引入包 
public interface NameOfInterface { 
//任何类型 final, static 字段 
//抽象方法
}

8.重写接口中声明的方法时,需要注意以下规则:
类在实现接口的方法时,不能抛出强制性异常,只能在接口中,或者继承接口的抽象类中抛出该强制性异常。
类在重写方法时要保持一致的方法名,并且应该保持相同或者相兼容的返回值类型。
如果实现接口的类是抽象类,那么就没必要实现该接口的方法。
9.24. 两两交换链表中的节点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

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

解题思路:这道题可以使用递归也可以使用迭代
方法一:使用迭代,设置虚拟头节点,设置一个临时节点,以临时节点的后两个节点为一组,将node1指向node2的后一个节点,再将node2指向node1,临时节点指向node2,再将临时节点移动到node1的位置上。时间复杂度为O(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 swapPairs(ListNode head) {
        ListNode dn = new ListNode(0, head);
        ListNode tmp = dn;
        while(tmp.next!=null && tmp.next.next!=null){
            ListNode n1 = tmp.next;
            ListNode n2 = tmp.next.next;
            n1.next = n2.next;
            n2.next = n1;
            tmp.next = n2;
            tmp = n1;
        }
        return dn.next;
    }
}

方法二:使用递归,以头节点和头节点的下一个节点NH为一组,将头节点的下一个节点指向递归函数的返回值,递归函数传入NH的下一个节点作为新的头节点,将NH的下一个节点指向头节点。时间复杂度是O(N)由于递归调用空间,空间复杂度也为O(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 swapPairs(ListNode head) {
        ListNode dn = new ListNode(0, head);
        if(head==null || head.next==null){
            return head;
        }
        ListNode nh = head.next;
        head.next =swapPairs(nh.next);
        nh.next = head;
        return nh;
    }
}

10.147. 对链表进行插入排序
对链表进行插入排序。
插入排序算法:
插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
重复直到所有输入数据插入完为止。

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

解题思路:遍历链表,设置虚拟头节点,指向头节点,设置head为最后一个排好序的节点lastS,head的下一个节点为目前节点cur,将现在的节点与lastS比较,如果大于last S,将last S后移一位,cur节点也后移一位,如果小于,通过虚拟头节点从头开始遍历链表,直到找到第一个比cur大的节点为止,将cur插入这个节点前面,将last S指向cur移动以前的下一个节点。时间复杂度是O(N^2),因为插入操作需要从头开始遍历链表。

/**
 * 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 insertionSortList(ListNode head) {
        
        if(head == null || head.next == null){
            return head;
        }
        ListNode dn = new ListNode(0,head);
        ListNode lastS = head;
        ListNode cur = lastS.next;
        while(cur != null){
            if(lastS.val <= cur.val){
                lastS = lastS.next;
            }
            else{
                ListNode pre = dn;
                while(pre.next.val <= cur.val){
                    pre = pre.next;
                }
                lastS.next = cur.next;
                cur.next = pre.next;
                pre.next = cur;
            }
            cur = lastS.next;
        }
        return dn.next;
    }
}

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

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

解题思路:使用归并排序,用递归来实现,设置两个指针,快指针指向链表的末尾,慢指针指向链表的中间位置,可以遍历链表,快指针一次移动两个节点,慢指针一次移动一个节点来实现。将链表分成两部分,分别递归,直到每一个链表里只有一个节点,这时一定是有序的,再通过合并算法,将每次两个链表合并起来形成一个有序链表,最终得到一个包含所有节点的有序链表。时间复杂度是归并排序的时间复杂度O(N log N),空间复杂度由于递归调用也是O(N log 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 sortList(ListNode head) {
        if(head == null){
            return null;
        }
        return sortList(head, null);
    }
    public ListNode sortList(ListNode head, ListNode tail){
            //使用递归实现归并排序
            ListNode fast = head;
            ListNode slow = head;
            if(head.next == tail){
                head.next = null;
                return head;
            }
            while(fast!=tail){
                fast = fast.next;
                slow = slow.next;
                if(fast!=tail){
                    fast = fast.next;
                }
            }
            ListNode mid = slow;
            ListNode list1 = sortList(head, mid);
            ListNode list2 = sortList(mid, tail);
            ListNode res = merge(list1, list2);
            return res;
        }
    public ListNode merge(ListNode list1, ListNode list2){
        ListNode head = new ListNode(0);
        ListNode dn = head;
        while(list1!=null && list2!=null){
           
            if(list1.val <= list2.val){
                head.next = list1;
                list1 = list1.next;
            }else{
                head.next = list2;
                list2 = list2.next;
            }
            head = head.next;
        }
        if(list1!=null){
                head.next = list1;
            }
            else if(list2!=null){
                head.next = list2;
            }
            
        return dn.next;
        
    }
}

晚上的时间总是过的很快,刚开始吃饭的时候,觉得时间非常充裕,慢悠悠地玩了一会儿手机,结果一瞬间,又到这个点了,还真是不能耽误片刻,今天上班居然忘记画眉毛,直到中午我才发现,然而可能根本都没有人关注吧,也有可能默默关注了没有说出来,写总结的时候总觉得自己都掌握了,前天的练习题,今天才做完,明天可以继续学习链表的下一节了,明日持续更新。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿达斯加

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值