1.哈希表简单介绍
哈希表在使用它层面上可以理解为一种集合结构
如果只有key,没有伴随数据value,可以使用hashSet结构(c++中叫unorderset)
如果有key,有伴随数据value,可以使用hashMap结构(c++中叫unorderMap)
有无伴随数据,是hashMap和hashSet唯一的区别,底层的实际结构是一回事。
使用哈希表增(put),删除(remove),改(put),查(get)的操作,可以认为时间复杂度为O(1),但是常数时间比较大。
放入哈希表的东西,如果是基础类型,内部按值传递,内存占用就是改值的实际大小。
放入哈希表的东西,不是基础类型,内部按照引用传递,内存占用就是这个东西的内存地址大小。
HashMap跟HashSet
HashSet:
HashSet实现了Set接口,它不允许集合中出现重复元素。当我们提到HashSet时,第一件事就是在将对象存储在HashSet之前,要确保重写hashCode()方法和equals()方法,这样才能比较对象的值是否相等,确保集合中没有
储存相同的对象。如果不重写上述两个方法,那么将使用下面方法默认实现:
public boolean add(Object obj)方法用在Set添加元素时,如果元素值重复时返回 “false”,如果添加成功则返回"true"
HashMap:
HashMap实现了Map接口,Map接口对键值对进行映射。Map中不允许出现重复的键(Key)。Map接口有两个基本的实现
TreeMap和HashMap。
TreeMap保存了对象的排列次序,而HashMap不能。HashMap可以有空的键值对(Key(null)-Value(null))HashMap是非线程安全的(非Synchronize),要想实现线程安全,那么需要调用collections类的静态方法synchronizeMap()实现。
public Object put(Object Key,Object value)方法用来将元素添加到map中。
HashSet与HashMap的区别:
HashMap使用键(Key)计算Hashcode. HashSet使用
成员对象
来计算hashcode值,. 对于两个对象来说hashcode可能相同,. 所以equals ()方法用来判断对象的相等性,. 如果两个对象不同的话,那么返回false. HashMap相对于HashSet较快,因为它是使用唯一的键获取对象. HashSet较HashMap来说比较慢.
2.有序表
有序表的操作都是O(logn)级别
//有序表
//常见的操作
TreeMap<Integer, String> treeMap1 = new TreeMap<>();
treeMap1.put(7, "我是7");
treeMap1.put(6, "我是6");
treeMap1.put(3, "我是3");
treeMap1.put(5, "我是5");
treeMap1.put(3, "我是3");
treeMap1.put(7, "我是7");
treeMap1.put(2, "我是2");
treeMap1.put(3, "我是3");
System.out.println(treeMap1.containsKey(5));
System.out.println(treeMap1.get(5));
System.out.println(treeMap1.firstKey() + "我最小");
System.out.println(treeMap1.lastKey() + " 我最大");
System.out.println(treeMap1.floorKey(8) + "在表中所有小于等于8的书中,离8最近的");
System.out.println(treeMap1.ceilingKey(8) + "在表中所有大于等于8的书中,离8最近的");
treeMap1.remove(5);
System.out.println(treeMap1.get(5) + ", 删掉就没有了");
题目一
//方法一
public static boolean isPalindrome1(Node head) {
Stack<Node> stack = new Stack<>();
Node cur = head;
while (cur != null) {
stack.push(cur);
cur = cur.next;
}
while (head != null) {
if (head.value != stack.pop().value) {
return false;
}
head = head.next;
}
return true;
}
//方式二
//need n/2 extra space
//找快慢指针
public static boolean isPalindrome2(Node head) {
if (head == null || head.next == null) {
return true;
}
Node right = head.next;
Node cur = head;
while (cur.next != null && cur.next.next != null) {
right = right.next;
cur = cur.next.next;
}
Stack<Node> stack = new Stack<>();
while (right != null) { //压栈
stack.push(right);
right = right.next;
}
while (!stack.isEmpty()) {
if (head.value != stack.pop().value) { //不等于 返回false
return false;
}
head = head.next;
}
return true;
}
//方式三
//need O(1) extra space
public static boolean isPalindrome3(Node head) {
if (head == null || head.next == null) {
return true;
}
Node n1 = head;
Node n2 = head;
while (n2.next != null && n2.next.next != null) { //find mid node
n1 = n1.next;
n2 = n2.next.next;
}
n2 = n1.next; //n1 ->mid
n1.next = null; //mid.next -> null
Node n3 = null;
while (n2 != null) { //right part convert
n3 = n2.next; //n3 -> save next node
n2.next = n1; //next of right node convert
n1 = n2; //n1 move
n2 = n3; //n2 move
}
n3 = n1; //n3->save last node
n2 = head; //n2 -> left first node
boolean res = true;
while (n1 != null && n2 != null) { //check paliindrome
if (n1.value != n2.value) {
res = false;
break;
}
n1 = n1.next; //left to mid
n2 = n2.next; //right to mid
}
n1 = n3.next;
n3.next = null;
while (n1 != null) {
n2 = n1.next;
n1.next = n2;
n3 = n1;
n1 = n2;
}
return res;
}
public static Node listPartition2(Node head, int pivot) {
Node sH = null; //samll head
Node sT = null; //small tail
Node eH = null; //equal head
Node eT = null; //equal tail
Node mH = null; //big head
Node mT = null; //big tail
Node next = null; //save next node
//every node distributed to three lists
while (head != null) {
next = head.next;
head.next = null;
if (head.value < pivot) {
if (sH == null) {
sH = head;
sT = head;
} else {
sT.next = head;
sT = head;
}
} else if (head.value == pivot) {
if (eH == null) {
eH = head;
eT = head;
}else {
eT.next =head;
eT = head;
}
}else {
if (mH == null){
mH =head;
mT = head;
}else {
mT.next = head;
mT = head;
}
}
head = next;
}
//small and equal reconnect
if (sT != null){ //如果有小于区域
sT.next = eH;
eT = eT ==null?sT:eT; //下一步,谁去连大于区域的头,谁就变成eT
}
//上面的if,不管跑了没有,et
//all reconnect
if (eT != null) { //如果小于区域和等于区域,不是都没有
eT.next = mH;
}
return sH != null ? sH : (eH != null ? eH : mH);
}
}
题目
class Node{
int value;
Node next;
Node rand;
Node(int val){
value = v
}
}
//hashmap实现问题
public static Node copyListWithRand1(Node head) {
HashMap<Node, Node> map = new HashMap<Node, Node>();
Node cur = head;
while (cur != null) { //将map对应关系记住
map.put(cur, new Node(cur.value));
cur = cur.next;
}
cur = head;
while (cur != null) {
//cur 老节点
//map.get(cur) 这种方式可以找到新结点
map.get(cur).next = map.get(cur.next); //新结点的next = 当前旧节点的next对应的新结点
map.get(cur).rand = map.get(cur.rand);
}
return map.get(head);
}
//不用哈希表的方式
public static Node copyListWithRand2(Node head) {
if (head == null) { //如果链表为空则返回空
return null;
}
Node cur = head;
Node next = null;
//copy node and link to every node
//1 -> 2
//1 -> 1` -> 2
while (cur != null) {
next = cur.next; //旧节点给了next
cur.next = new Node(cur.value); //原next位置放入新节点
cur.next.next = next; //旧节点给next next
cur = next; //转移指针
}
cur = head;
Node curCopy = null;
//set copy node rand
//1->1`->2->2`
while (cur != null) {
next = cur.next.next;
curCopy = cur.next;
curCopy.rand = (cur.rand != null) ? cur.rand.next : null;
cur = next;
}
}