文章只是总结,便于面试和手写算法。细节和详细解释,请看:https://leetcode-cn.com/
1. 题目
算法题:
1. 反转链表:https://leetcode-cn.com/problems/reverse-linked-list/
2. 两两交换链表中的节点:https://leetcode-cn.com/problems/swap-nodes-in-pairs/
3. 判断链表是否有环:https://leetcode-cn.com/problems/linked-list-cycle/
4. K 个一组翻转链表:https://leetcode-cn.com/problems/reverse-nodes-in-k-group/
面试题:
1. Set是如何保证里面的元素唯一
2. 以登录界面为例子,设计MVP架构
2. 基本知识
2.1 数组
内存中的连续存储空间。
- 查询时间复杂度:O(1)
- 插入、删除时间复杂度:O(n)
2.3 链表
内存中非连续、非顺序的存储结构,数据原生的顺序通过链表中的指针链接次序实现。有单链表和双链表。适用于频繁插入删除,查询次数不多的场景。
- 查询:O(n)
- 插入、删除:O(1)
3. 算法题解题
3.1 反转链表
假设存在链表 1 → 2 → 3 → Ø,我们想要把它改成 Ø ← 1 ← 2 ← 3。把每个节点的next指向它的前一个节点即可。
该题解,时间复杂度O(n),空间复杂度O(1)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre = null;
ListNode cur = head;
while(cur != null){
ListNode nextTemp = cur.next;
cur.next = pre;
pre = cur;
cur = nextTemp;
}
return pre;
}
}
3.2 两两交换链表中的节点
递归解法:最小递归单元中,next链接head,然后前面换好的节点连接上next。
该题解时间复杂度O(n),空间复杂度O(1)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode swapPairs(ListNode head) {
if(head == null || head.next == null)
{
return head;
}
ListNode next = head.next;
head.next = swapPairs(next.next);
next.next = head;
return next;
}
}
3.3 判断链表是否有环
1->2->3->4和1->2->3->1->2的区别
第一种解法:使用一个set来存储ListNode节点,每次拿到当前节点,去set中查询是否重复,如果有,则重复
该解法时间复杂度O(n) 空间复杂度O(n)
public class Solution {
public boolean hasCycle(ListNode head) {
HashSet hashSet = new HashSet();
while(head!= null){
if (hashSet.contains(head)) {
return true;
}else{
hashSet.add(head);
}
head = head.next;
}
return false;
}
}
第二种解法:使用两个指针,一个快指针,一个慢指针,如果最后快慢指针相遇,则说明有环,否则无环
该解法时间复杂度为O(n) 空间复杂度为O(1)
public class Solution {
public boolean hasCycle(ListNode head) {
if (head == null || head.next == null) {
return false;
}
ListNode slow = head.next;
ListNode fast = head;
while(slow != fast){
if (slow == null || fast == null) {
return false;
}
slow = slow.next;
fast = fast.next.next;
}
return true;
}
}
3.4 K个一组反转链表
示例 :
给定这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
解法:获取链表长度,除以k,得到有多少个需要翻转的子链表,子链表翻转完成后,拼接上之前剩余的链表即可
public ListNode reverseKGroup(ListNode head, int k) {
if (head == null)
return null;
// 1.获得链表节点个数
int count = 0;
ListNode cur = head;
while (cur != null) {
count++;
cur = cur.next;
}
// 2.获得需要翻转的组数
int group = count / k;
ListNode fakeHead = new ListNode(0), pre = fakeHead;
cur = head;
fakeHead.next = head;
// 3.开始翻转
while (group-- > 0) {
// 3.1 组内翻转k-1次
for (int i = 0; i < k - 1; i++) {
ListNode tmp = cur.next;
cur.next = tmp.next;
tmp.next = pre.next;
pre.next = tmp;
}
// 3.2 开始下一次翻转
pre = cur;
cur = cur.next;
}
return fakeHead.next;
}
4. 面试题解题
4.1 Set是如何保证里面的元素唯一
set保证里面元素的唯一性其实是靠两个方法,一是equals()和hashCode()方法
往set里面添加数据的时候一般会有隐式的操作
先是判断set集合中是否有与新添加数据的hashcode值一致的数据,
如果有,那么将再进行第二步调用equals方法再进行一次判断,
假如集合中没有与新添加数据hashcode值一致的数据,那么将不调用eqauls方法。
4.2 以登录界面为例子,设计MVP架构
明天补上,今天太晚了