JAVA JDK中List接口下面有两个实现类,分别是ArrayList和LinkedList。其中,ArrayList实现了随机访问的接口,LinkedList实现了Quene的接口。ArrayList是基于数据实现的list,而LinkedList是基于链表实现的list。所以,ArrayList拥有着数组的特性,LinkedList拥有着链表的特性。
问题一:关于数组的动态扩容以及增删改查
我是仿照JDK源码,实现了一下两个功能:
1、实现一个支持动态扩容的数组
2、实现一个大小固定的有序数组,支持动态增删改操作
package codingTest;
public class expandArrayList {
private Object[] elementData;//数组
private int size;
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
//1、数组扩容和数据的拷贝
private void ensureCapacity() {
if(size == elementData.length) {
Object[] newArray = new Object[(size+1)*2];
// System.arraycopy(elementData, 0, newArray, 0, elementData.length);//老数组copy到新数组这个位置
for(int i = 0; i < elementData.length; i++) {
newArray[i] = elementData[i];
}
elementData = newArray;
}
}
//2、实现一个大小固定的有序数组,支持动态增删改操作
//准备一个空构造器
public expandArrayList() {
this(10);//默认数组的长度是10
}
//准备一个带参构造器
public expandArrayList(int initalCapacity) {
if(initalCapacity < 0) {
try {
throw new Exception();
} catch (Exception e) {
e.printStackTrace();
}
}
elementData = new Object[initalCapacity];
}
//获取指定位置的元素
public Object get(int index) {
rangeCheck(index);
return elementData[index];
}
//改动指定的对象
public Object set(int index, Object obj) {
rangeCheck(index);
Object oldValue = elementData[index];
elementData[index] = obj;
return oldValue;
}
//删除指定的位置上的数
public void remove(int index) {
rangeCheck(index);
int numMoved = size - index - 1;
if(numMoved > 0) {
System.arraycopy(elementData, index+1, elementData, index, numMoved);
}
elementData[--size] = null;
}
//删除指定的对象
public void remove(Object obj) {
for(int i = 0; i < size; i++) {
if(get(i).equals(obj)) {//底层调用的是equals方法,而非==
remove(i);
}
}
}
//在数组末尾增加元素
public void add(Object obj) {
ensureCapacity();
elementData[size] = obj;
size++;
}
//插入指定的对象
public void insert(int index, Object obj) {
rangeCheck(index);
ensureCapacity();
System.arraycopy(elementData, index, elementData, index+1, size - index);
elementData[index] = obj;
size ++;
}
//数组范围检查
private void rangeCheck(int index) {
if(index < 0 || index >= size) {
try {
throw new Exception();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
expandArrayList expandList = new expandArrayList(3);
expandList.add(2);
expandList.add(32);
expandList.add(4);
expandList.add(5);
System.out.println(expandList.size());
System.out.println(expandList.get(3));
System.out.println("------------------------");
for(int i = 0; i < expandList.size; i++) {
System.out.println(expandList.get(i));
}
System.out.println("------------------------");
expandList.insert(1, "kkk");
for(int i = 0; i < expandList.size; i++) {
System.out.println(expandList.get(i));
}
}
}
问题二:双向链表的增删改查
我是仿照LinkedList的jdk写的:
package codingTest;
public class Node {
Node previous;
Object obj;
Node next;
public Node(){
}
//构造方法
public Node(Node previous, Object obj, Node next){
super();
this.previous = previous;
this.obj = obj;
this.next = next;
}
//get与set方法
public Node getPrevious() {
return previous;
}
public void setPrevious(Node previous) {
this.previous = previous;
}
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
package codingTest;
public class twowayLinkedList {
private Node first;
private Node last;
private int size;
//插入
public void insert(int index, Object obj) {
Node temp = ergodicNode(index);
Node newNode = new Node();
newNode.obj = obj;
if(temp != null) {
Node former = temp.previous;
former.next = newNode;
newNode.previous = former;
newNode.next = temp;
temp.previous = newNode;
}
size ++;
}
//删除
public void remove(int index) {
rangeCheck(index);
Node temp = ergodicNode(index);
if(temp != null) {
//首先获得上一个节点
Node former = temp.previous;
//获得下一个节点
Node latter = temp.next;
//下一个节点的先驱节点付给前一个节点的后继结点
former.next = latter;
latter.previous = former;
size--;
}
}
//遍历节点并返回对应index的节点
public Node ergodicNode(int index) {
Node temp = null;
if(first != null) {
temp = first;
for(int i = 0; i < index; i++){
temp = temp.next;
}
}
return temp;
}
//根据索引获取相对应的值
public Object get(int index) {
rangeCheck(index);
Node temp = ergodicNode(index);
if(temp != null) {
return temp.obj;
}
return null;
}
//增加操作
public void add(Object obj) {
if(first == null) {
Node n = new Node();
n.setPrevious(null);
n.setObj(obj);
n.setNext(null);
first = n;
last = n;
}else {
//直接往last节点后面增加新的节点
Node n = new Node();
n.setPrevious(last);
n.setObj(obj);
n.setNext(null);
last.setNext(n);
last = n;
}
size ++;
}
//获取该List中的元素个数
public int size() {
return size;
}
//检查是否越界
public void rangeCheck(int index) {
if(index < 0 || index > size) {
try {
throw new Exception();
} catch (Exception e) {
e.printStackTrace();
}
}
}
//测试类
public static void main(String[] args) {
twowayLinkedList myLinkedList = new twowayLinkedList();
myLinkedList.add("aaa");
myLinkedList.add("bbb");
myLinkedList.add("ccc");
System.out.println(myLinkedList.size());
System.out.println(myLinkedList.get(1));
myLinkedList.remove(1);
System.out.println(myLinkedList.get(1));
myLinkedList.insert(1, "ddd");
System.out.println(myLinkedList.get(1));
System.out.println(myLinkedList.get(2));
}
}
问题三:反转单向链表
package codingTest;
public class reverseSingleLink {
public static class Node {
public int value;
public Node next;
public Node(int data) {
this.value = data;
}
}
public static int reverse(Node head) {
Node pre = head.next;
Node now = head;
if(now != null) {
Node temp = now.next;
now.next = pre;
pre = now;
now = now.next;
}
return pre.value;
}
// public static Node reverse(Node head) {
// if(head == null) {
// return null;
// }
//
// Node pre = null;
// Node cur = head;
// Node reHead = null;
//
// //如果当前节点为空,结束循环
// while(cur != null) {
// //保存下一个结点,以免丢失
// Node temp = cur.next;
// //1.对pre和cur结点的关系进行反转。本来是pre指向cur的,用下面这条代码能够把cur指向pre。
// cur.next = pre;
// //2.如果下一个结点为空,那他就是反转链表的头结点
// if(cur.next == null) {
// reHead = cur;
// }
// //3.上一个结点已经反转完成啦!现在要移动到下一个结点了!
// pre = cur;
// cur = temp;
// }
// return reHead;
// }
//
// static Node reverse(Node head) {
// Node pre = null;
// Node temp = null;
//
// while(head != null){
// //1.记录下一个结点
// //2.指针反转
// temp = head.next;
// head.next = pre;
//
// //3.光标移向原链表的下一个结点
// pre = head;
// head = temp;
// }
//
// return pre;
// }
public static void main(String[] args) {
Node node = new Node(1);
node.next = new Node(2);
node.next.next = new Node(3);
node.next.next.next = new Node(4);
System.out.println(reverse(node));
}
}
Leetcode 求众数
给定一个大小为 n 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋
的元素。你可以假设数组是非空的,并且给定的数组总是存在众数。
示例 1:
输入: [3,2,3]
输出: 3
示例 2:
输入: [2,2,1,1,1,2,2]
输出: 2
package codingTest;
import java.util.HashMap;
import java.util.Map;
public class majorityNumber_leetcode {
//2、哈希表法
public static Map<Integer, Integer> countNums(int[] nums) {
Map<Integer, Integer> counts = new HashMap<Integer, Integer>();
for (int num : nums) {
if (!counts.containsKey(num)) {
counts.put(num, 1);
}
else {
counts.put(num, counts.get(num)+1);
}
}
return counts;
}
public static int majorityNum(int[] nums) {
Map<Integer, Integer> counts = countNums(nums);
Map.Entry<Integer, Integer> majorityEntry = null;
for (Map.Entry<Integer, Integer> entry : counts.entrySet()) {
if (majorityEntry == null || entry.getValue() > majorityEntry.getValue()) {
majorityEntry = entry;
}
}
return majorityEntry.getKey();
}
//方法一:暴力破解法
// public static int majorityNum(int[] nums) {
// int majorityCount = nums.length / 2;
//
// for(int num : nums) {
// int count = 0;
// for(int elem : nums) {
// if(elem == num) {
// count += 1;
// }
// }
//
// if(count > majorityCount) {
// return num;
// }
//
// }
//
// return -1;
//
// }
public static void main(String[] args) {
int[] nums = {2, 3, 4, 4, 5, 1, 4, 4, 4};
System.out.println(majorityNum(nums));
}
}
Leetcode 环形链表
给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 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
解释:链表中没有环。
public boolean hasCycle(ListNode head) {
Set<ListNode> nodes = new HashSet<>();
while (head != null) {
if (nodes.contains(head)) {
return true;
} else {
nodes.add(head);
}
head = head.next;
}
return false;
}