数据结构
链表
- resursion 递归的原理;细节
/*Calculating Fibonacci value
int fibo(int n){ //检查check是否要停下,
if(n == 0)retutn 0; //base case o(1)
else if{n ==1}
else{
return fibo(n-1)+fibo(n-2); }
}
Call stack; //全局的变量,Usage; store the local information for each recursion function
F(4)
// \\
F(3) F(2 )
/ \ \
F(2) F(1)
question 1: interview question on linkedlist:how to reserver a linked list
node1 -> node2 ->node3 ->node4 ->null
head
pre cur next
pre (a) cur(temp) next(b)
public linkNode reverseLinkdelist(linkedNode head){
if(head == null||head.next) return head;
linkedNode pre = null;
linkedNode cur = head;
while(cur!=null){
LinkedNode next = cur.next;//记录next的值。
cur.next = pre;
pre = cur;
cur = next;
}
}
method:递归
before node1 ->node2 ->node3 ->null
after null <- node1 < - node2 <- node3
next.next = head;
next. = null;
public static LinkedNode reserverLinked(LinkedNode head){
if(head==null||head.next==null)return head;
LinkedNode new_head = resercerLinked(head.next);
head.next.next = head;
head.next = null;
return new_head;
}
question 2How to create a linked list node
class Node{
int no ;
String name;
Node next;
public Node(int no,String name){
this.no = no;
this.name = name;
}
public String toString() {
return "HeroNode [no= " + no + "name =" + name + "]";
}
}
question 3How to add data
public static void add(LinkedNode value){
LinkedNode temp = value;
while(temp.next!=null){
temp = temp.next;
}
temp.next = head;
}
question How to find the middle node of a linked list?
N1 ->N2 ->N3 ->N4 ->N5 ->null
fast
slow
N1 ->N2 ->N3 ->N4 ->N5 ->null
sl
public static Node middle(Node head){
if (head==null)return null;
Node fast = head;
Node slow = head;
while (fast.next!=null && fast.next.next!=null){
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
question:判断是否有环
public boolean hasCycle(ListNode head) {
if (head == null || head.next == null) {
return false;
}
ListNode slow = head;
ListNode fast = head.next;
while (slow != fast) {
if (fast == null || fast.next == null) {
return false;
}
slow = slow.next;
fast = fast.next.next;
}
return true;
}
question :insert a node in a sort linked;
public static Node insert(Node head ,Node a){
if (head == null || a == null)return null;
boolean flag = false;
Node temp = head;
while (true){
if (temp.next==null)break;
if (a.no>temp.no&&a.no<=temp.next.no)break;
if (a.no > temp.no &&a.no<=temp.next.no){
flag=true;
break;
}
temp = temp.next;
}
if (flag){
return null;
}
else {
a.next = temp.next;
temp.next = a;
return head;
}
}
question How to list data
public static void list(){
if(head==null){
System.out.println("空");
return;
}
Node temp = head;
while(true){
if (temp!=null) {
System.out.println(temp);
temp = temp.next;
}
}
}
question ;How to merger tow lists?
public static Node newLinked(Node head,Node head1) {
Node ss = new Node(-1, "aa");
Node s = ss;
while (head!=null&&head1!=null){
if (head.no>=head1.no){
s.next = head1;
head1 = head1.next;
s=s.next;
}else {
s.next = head;
head = head.next;
s=s.next;
}
}
s.next = (head!=null)?head:head1;
return ss.next;
}
public static Node newLinked(Node head, Node head1) {
if (head == null) return head1;
if (head1 == null) return head;
if (head.no < head1.no) {
head.next = newLinked(head.next, head1);
return head;
} else {
head1.next = newLinked(head, head1.next);
return head1;
}
}
判断字符串String是否为空问题
判断字符串String是否为空问题
一、判断一个字符串str不为空的方法有:
1、str == null;
2、"".equals(str);
3、str.length <= 0;
4、str.isEmpty();
注意:length是属性,一般集合类对象拥有的属性,取得集合的大小。
例如:数组。length就是取得数组的长度。
length()是方法,一般字符串类对象有该方法,也是取得字符串长度。
例如:字符串。length();
说明:
1、null表示这个字符串不指向任何的东西,如果这时候你调用它的方法,那么就会出现空指针异常。
2、""表示它指向一个长度为0的字符串,这时候调用它的方法是安全的。
3.、null不是对象,"“是对象,所以null没有分配空间,”"分配了空间,例如:
String str1 = null; str引用为空
String str2 = ""; str引用一个空串
str1还不是一个实例化的对象,而str2已经实例化。
对象用equals比较,null用等号比较。
如果str1=null;下面的写法错误:
if(str1.equals("")||str1null){ }
正确的写法是 if(str1null||str1.equals("")){ //所以在判断字符串是否为空时,先判断是不是对象,如果是,再判断是不是空字符串 }
4.所以,判断一个字符串是否为空,首先就要确保他不是null,然后再判断他的长度。
String str = xxx;
if(str != null && str.length() != 0)
排序
快排
连接:https://www.bilibili.com/video/BV1at411T75o? from=search&seid=3067293629631568894
private static int Partition(int[] arr, int start, int end) {
//arr[start]为挖的第一个坑
int temp = arr[start];
while (end > start){
while(end > start&&arr[end]>=temp)
end--;
arr[start] = arr[end];
while (end>start&&arr[start]<=temp)
start++;
arr[end] = arr[start];
}
arr[start] = temp;
return start;
}
public static void quickSort(int[] arr, int start ,int end){
if (start < end){
int index = Partition(arr,start,end);
Partition(arr,start,index-1);
Partition(arr,index+1,end);
}
}
选择排序
public static void main(String[] args) {
int[] arr = {2, 5, 3, 5, 1, 5, 6};
for (int i = 0; i < arr.length; i++) {
//先设定最小值,和索引
int min = arr[i];
int index = i;
for (int j = i + 1; j < arr.length; j++) {
//将最小值交换下
if (min > arr[j]) {
min = arr[j];
index = j;
}
}
//判断是否交换没,交换了再进行交换
if (index != i) {
arr[index] = arr[i];
arr[i] = min;
}
}
System.out.println(Arrays.toString(arr));
}
public static void sortMrger(int[] arr, int left, int right, int[] temp) {
if (left <right) {
int mid = left +(right - left) /2;
sortMrger(arr, left, mid, temp);
sortMrger(arr, mid + 1, right, temp);
merge(arr, left, mid, right, temp);
}
}
public static void merge(int[] arr, int left, int mid, int right, int[] temp) {
//创建左半部分的最高索引
int i = mid + 1;//初始化右边的,因为在左边的第一个
int j = left;
//设置索引
int t = 0;
while (i <=right && j <= mid) {
if (arr[i] <= arr[j]) {
temp[t] = arr[i];
i++;
t++;
}
if (i<=right&&arr[i] >= arr[j]) {
temp[t] = arr[j];
j++;
t++;
}
}
while (j <= mid) {
temp[t] = arr[j];
j++;
t++;
}
while (i <= right) {
temp[t] = arr[i];
i++;
t++;
}
int r = left;
t = 0;
while (r <= right) {
arr[r] = temp[t];
r++;
t++;
}
}
冒泡排序
public class 冒泡排序 {
public static void main(String[] args) {
int[] arr = {2, 5, 3, 5, 7, 8, 6};
int temp = 0;
boolean flag = false;//如果只有一个数交换,不需要一直遍历,来减轻方便的
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr.length - 1; j++) {
if (arr[j] > arr[j + 1]) {
flag = true;
temp = arr[j + 1];
arr[j + 1] = arr[j];
arr[j] = temp;
}
}
if (!flag) {
break;
} else {
flag = false;
}
}
System.out.println(Arrays.toString(arr));
}
堆排序
public static void main(String[] args) {
int[] arr= {2,5,3,6,4,1,2,8};
new HeapSort().heap(arr);
System.out.println(Arrays.toString(arr));
}
}
class HeapSort{
public void heap(int[] arr){
int temp = 0;//交换最后一个值后第一个值的临时变量
for(int i = arr.length/2-1;i>=0;i--){
heapSort(arr,i,arr.length);//先求出第一次的头
}
for(int j = arr.length - 1; j > 0;j--){
temp = arr[j];
arr[j] = arr[0];
arr[0] = temp;
heapSort(arr,0,j);//出去最后一个值后缩小索引
}
}
public void heapSort(int[] arr, int i, int leng) {
/*
思路: 先将从最后一个非叶子结点开始,arr.length/2 - 1,从左到右,从下到上
*/
//设定一个临时变量来放顶头值
int temp = arr[i];
//将当前的顶结点的值给算出来
for (int k = i * 2 + 1; k < leng; k *= 2 + 1) {
//k+1总是会小于leng。当不是满二叉树,不需要判断了
if (k + 1 < leng && arr[k] < arr[k + 1]) {
k = k + 1;
}
if (arr[k] > temp) {
arr[i] = arr[k];
i = k;//将交换的数值后索引交换
} else {
break;
}
}
arr[i] = temp;
}
插入排序
public static void main(String[] args) {
int[] arr = {2, 5, 3, 6, 4, 2, 5, 1, 2};
charu(arr);
System.out.println(Arrays.toString(arr));
}
public static void charu(int[] arr){
for (int i = 1;i<arr.length;i++){
int temp = arr[i];
int index = i -1;
while (index >= 0 && arr[index]>=temp){
arr[index+1] = arr[index];
index--;
}
arr[index+1] = temp;
}
}
queue stack deque
linkedlist 可以添加null,arrayQueue不可以
peek 是返回顶点元素 , 不会删除的,pop 是返回你取得元素,还要删除呢
queue 和 stack ,deque(deck发音)实现类Linkedlist 和arrayDueue
Queue<Integer> queue = new LinkedList<>();
queue.offer(1);
queue.offer(2);
queue.offer(3);
while (!queue.isEmpty()){
System.out.println(queue.peek());
System.out.println(queue.poll());
}
System.out.println(queue.peek());
System.out.println(queue.poll());
Deque<Integer> deque = new LinkedList<>();
deque.offerFirst(1);
deque.offerFirst(2);
deque.offerFirst(3);
deque.offerLast(4);
deque.offerLast(5);
deque.offerLast(6);
for (int i = 0;i<deque.size();i++){
if (i%2==0){
System.out.println(deque.peekFirst());
System.out.println(deque.pollFirst());
}
}
class ListNode{
int value;
ListNode next;
public ListNode(int value){
this.value = value;
}
}
class Stack{
ListNode head ;
public Stack(){
head = new ListNode(1);
head.next = null;
}
public void push(int value){
ListNode newNode = new ListNode(value);
newNode.next = head.next;
head.next = newNode;
}
public Integer pop(){
ListNode temp = head.next;
if (head.next == null){
return null;
}
head.next = temp.next;
temp.next = null;
return temp.value;
}
public Integer peek(){
return head.next.value;
}
tree
但是,二叉搜索树对哈希表的性能很好:
- 二进制搜索树永远不会遇到冲突,这意味着二进制搜索树可以保证在O(log(n))中实现插入,检索和删除,这比线性时间快得多。此外,树所需的空间与输入数据的大小完全相同。
- 您无需事先知道输入大小。
- 对树中的所有元素进行排序,以使有序遍历花费O(n)时间。
好,让我做一个总结。
如果您知道要维护多少数据,并且有足够的空间存储哈希表并且不需要对数据进行排序,那么哈希表始终是不错的选择。因为,哈希表为插入,检索和删除提供了恒定时间的操作。另一方面,如果将始终添加项,则与运行时的哈希处理操作相比,二叉搜索树的O(log(n))操作是可以接受的。
此外,如果您实际上不知道输入项目的大小,但是在插入后,大多数操作都是在查找项目,由于检索时间恒定,因此首选哈希表。但是,如果连续添加或删除项目,则树的O(log(n))插入和删除时间更适合这种情况。
一言以蔽之,没有人会回答哈希表或树更好。我们需要知道的是在不同条件下哈希表和树的优缺点。可以通过了解这两种结构的利益和权衡来做出最佳决策。
一种二叉查找树,但在每个节点增加一个存储位表示节点的颜色,可以是红或黑(非红即黑)。通过对任何一条从根到叶子的路径上各个节点着色的方式的限制,红黑树确保没有一条路径会比其它路径长出两倍,因此,红黑树是一种弱平衡二叉树(由于是弱平衡,可以看到,在相同的节点情况下,AVL树的高度低于红黑树),相对于要求严格的AVL树来说,它的旋转次数少,所以对于搜索,插入,删除操作较多的情况下,我们就用红黑树。
Attention:
- 平衡树(AVL)是为了解决 二叉查找树(BST)退化为链表的情况。
- 红黑树(RBT)是为了解决 平衡树 在删除等操作需要频繁调整的情况
查找多的话用 AVL ,
添加删除多的话用 RB。
二叉树 | 满二叉树 | 完全二叉树 | 堆和堆排序 | |
---|---|---|---|---|
定义 | 二叉树是节点的有限集合,该集合或为空集,或由一个根元素和两棵不相交的二叉树组成(递归定义)二叉树的两棵子树分别称为它的左子树和右子树 | 一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是(2^k) -1 ,则它就是满二叉树。 | 一棵二叉树至多只有最下面的两层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上,则此二叉树成为完全二叉树,并且最下层上的结点都集中在该层最左边的若干位置上,而在最后一层上,右边的若干结点缺失的二叉树,则此二叉树成为完全二叉树。 [1] | 堆的结构可以分为大根堆和小根堆,是一个完全二叉树,而堆排序是根据堆的这种数据结构设计的一种排序,下面先来看看什么是大根堆和小根堆 |
性质 | 性质1. 非空二叉树第 i 层上至多有 2i 个结点(i ≥ 0)性质2. 高度为 k 的二叉树至多有 2k-1 个结点(k ≥ 0)性质3. 对任何非空二叉树 T,若其叶结点个数为 n0,度数为 2 的结点个数为 n2,则n0 = n2 + 1性质4. n 个结点的完全二叉树的高度 k = ⎡log2(n+1)⎤性质5. 满二叉树里的叶结点比分支结点多一个 | 如果一棵具有n个结点的深度为k的二叉树,它的每一个结点都与深度为k的满二叉树中编号为1~n的结点一一对应,这棵二叉树称为完全二叉树。可以根据公式进行推导,假设n0是度为0的结点总数(即叶子结点数),n1是度为1的结点总数,n2是度为2的结点总数,则 :①n= n0+n1+n2 (其中n为完全二叉树的结点总数);又因为一个度为2的结点会有2个子结点,一个度为1的结点会有1个子结点,除根结点外其他结点都有父结点,②n= 1+n1+2n2 ;由①、②两式把n2消去得:n= 2n0+n1-1,由于完全二叉树中度为1的结点数只有两种可能0或1,由此得到n0=n/2 或 n0=(n+1)/2。简便来算,就是 n0=n/2,其中n为奇数时(n1=0)向上取整;n为偶数时(n1=1)向下取整。可根据完全二叉树的结点总数计算出叶子结点数。 | 查找数组中某个数的父结点和左右孩子结点,比如已知索引为i的数,那么1.父结点索引:(i-1)/2(这里计算机中的除以2,省略掉小数)2.左孩子索引:2i+13.右孩子索引:2i+2所以上面两个数组可以脑补成堆结构,因为他们满足堆的定义性质:大根堆:arr(i)>arr(2i+1) && arr(i)>arr(2i+2)小根堆:arr(i)<arr(2i+1) && arr(i)<arr(2i+2) | |
优点 | 二叉排序树是一种比较有用的折衷方案。数组的搜索比较方便,可以直接用下标,但删除或者插入某些元素就比较麻烦。链表与之相反,删除和插入元素很快,但查找很慢。二叉排序树就既有链表的好处,也有数组的好处。在处理大批量的动态的数据是比较有用 | |||
缺点 | 缺点:顺序存储可能会浪费空间(在非完全二叉树的时候),但是读取某个指定的节点的时候效率比较高O(0)链式存储相对二叉树比较大的时候浪费空间较少,但是读取某个指定节点的时候效率偏低O(nlogn) | 最差时间也是nlogn 但是建立堆需要时间, | ||
没有快排好 | ||||
记住 | 前序后序遍历 |
1 二叉树的性质 : 叶子结点个数为n0 , 度为1的个数为n1 , 度为2的个数 为n2
/ 边 \ n = n0 + n1 + n2 ;//不是指一个,总数
2 3 边 = n1 + 2 * n 2 // 头结点上面啥都没
/ \ 因为头结点上面啥都没,所以可以化为 n - 1
4 5 n -1 = n1+2 * n2 = n0 + n1 + n2 -1
||
n0 = n2 + 1;
完全二叉树的性质 : 度为 1 的 结点个数 为 0 和 1
n0 = n2 + 1; n = n0 + n1 + n2 ==> n = 2 n0 +n1 - 1 ;
判断是否为完全二叉树
import java.util.LinkedList;
import java.util.Queue;
/**********************************************************
* 非递归方法,基本是层次遍历二叉树 依次检查每一个节点:
* 1.当发现有一个节点的左子树为空,右子树不为空时 直接返回false.
* 2.当发现有一个节点的左子树不为空,右子树为空时,置标志位为1。
* 3.当发现有一个节点的左右子树均为空时,置标志位为1。
**********************************************************/
public class CompleteBinaryTree
{
//检查一棵树是不是完全二叉树
public boolean checking(TreeNode root)
{
Queue<TreeNode> queue = new LinkedList<TreeNode>();
boolean flag = false; // 叶子结点 TreeNode left;
TreeNode right;
queue.add(root);
while (!queue.isEmpty()) {
root = queue.poll();
left = root.left;
right = root.right;
if ((flag && (left != null || right != null)) || (left == null && right != null)) {
// 如果之前层遍历的结点没有右孩子,且当前的结点有左或右孩子,直接返回false
// 如果当前结点有右孩子却没有左孩子,直接返回false
return false;
}
if (left != null) queue.offer(root.left);
if (right != null)queue.offer(root.right);
else flag = true; // 如果当前结点没有右孩子,那么之后层遍历到的结点必须为叶子结点
}
return true;
}
}
public static int getHigh(TreeNode root) { 0 // 第一步,直接到3下面 判断3的左右的结点为空,再走到下一步 再判断 返回 1
if (root == null) return 0; / \ // 第二步,返回到了1 判断右边 ,同样道理 ,然后返回1 , 之后比较 加一后 返回到1结点的
int leftHigh = getHigh(root.left); 1 2 //值为2;
int rightHigh = getHigh(root.right); / \ / \ //依次
return Math.max(leftHigh, rightHigh) + 1; 3 4 5 6
}
BFS 和 DFS
DFS : 基本方法每层代表什么状态和需要多少层
BFS 和 DFS 区别一个层遍历一个一头扎下底的,
bfs
public static TreeNode Search (TreeNode root){
//base case
if (root==null)return null;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
TreeNode left;
TreeNode right;
while (!queue.isEmpty()){
int stem = queue.size();
for (int i = 0; i < stem; i++) {
TreeNode a = queue.poll();
if (a.left!=null){
queue.add(a.left);
}
if (a.right!=null){
queue.add(a.right);
}
System.out.print(a.val);
}
System.out.println();
}
return null;
}
判断完全二叉树
class Solution{
public static boolean isComplementTree(TreeNode root){
//base case
if(root == null)return false;
Queue<TreeNode> queue = new LinkedList<>();
TreeNode nodeLeft = null;
TreeNode nodeRight = null;
queue.add(root);
boolean falg = false;
while(!queue.isEmpty()){
TreeNode node = queue.poll();
nodeLeft = node .left;
nodeRight = node.right;
if(falg&&(nodeLeft!=null||nodeRight!=null)||(nodeLeft==null&&nodeRight!=null)){
return false;
}
if(nodeLeft!=null){
queue.add(nodeLeft);
}
if (nodeRight!=null){
queue.add(nodeRight);
}else{
falg = true;
}
}
return true;
}
}
dfs
//题目:求abc可以任意取
class Culotion{
public static void findSubset(String[] str , int index , StringBuffer sbf){//取StringBuffer因为排列的顺序
if (index == str.length){ //
if (sbf.length() == 0){
System.out.println("kong");
}else {
System.out.println(sbf.toString());
}
return;
}
sbf.append(str[index]); //添加元素
findSubset(str,index+1,sbf);
sbf.deleteCharAt(sbf.length() -1 ); //返回到上层
findSubset(str,index+1,sbf);
}
abc
ab
ac
a
bc
b
c
kong
//题目:给出数,求出多少对()的排序
Dfs(3,0,0,s);
}
public static void Dfs(int n , int l , int r , StringBuffer s){
if (l == n && r == n){ //左右边等于其数时
System.out.println(s);
return;
}
if (l<n){
s.append("(");
Dfs(n,l+1,r,s);
s.deleteCharAt(s.length()-1);
}
if (r<l){ //如何判断要不要加右边,添加到左边的( 要大于)才可以,不要数后面的
s.append(")");
Dfs(n,l,r+1,s);
s.deleteCharAt(s.length() -1);
}
}
//题目;求有25,10,5,1 来构成99的组合
public static void synthetic(int numerical , int level , int temp[]){
if(level == 3){
temp[level] = numerical; //为一时候不需要循环直接打印了
System.out.println(Arrays.toString(temp));
return;
}
for (int i = 0 ; i <= numerical/coin[level] ; i++){ //用来分成的
temp[level] = i;
synthetic (numerical - coin[level]*i , level +1 , temp);
}
}
//求排列组合,abc的组合
public static void jiaohuan(int index , String[] str,StringBuffer sbf ){
if (index == 3){
System.out.println(Arrays.toString(str));
return;
}
for (int i = index ; i < str.length ; i++){ //一定要从index开始,因为去掉前面的定长
swap(str,index,i);
jiaohuan(index + 1 ,str,sbf);
}
}
public static String[] swap(String[] s , int index , int i){
String temp ;
temp = s[index];
s[index] = s[i];
s[i] = temp;
return s;
public static void combination(String[] str , int level , StringBuffer sbf,boolean[] bl){
if (level == 3){
System.out.println(sbf);
return;
}
for(int i = 0 ; i < str.length ; i++){
if (bl[i] == false){
sbf.append(str[i]);
bl[i] = true;
combination(str,level+1,sbf,bl);
bl[i] = false;
sbf.deleteCharAt(sbf.length() - 1);
}
}
}
可选不可选,for循环n叉树,swap选择重复的元素,组合多用
查目标数
1题目: 1 2 3 4
5 6 7 8 找到目标数字6,判断是否有
9 10 11 12
//1. 二位数组 [2][3] size = 12 index = 11;
targer = 6 m = 4 n = 3
left = 0; right = n*m -1 - 1;
// mid = (l+r)/2 = 5 5/col = 5/4 = 1 ->row 5%col = 5%col = l -> col //返回值的行和列
public boolean ifFind (int[][] matix ,int target){
if(matix.length == null || matix[0].length == 0)return false;//判断长度为0和数组为空
int row = matix.length; int col = matix[0].length; // 二维数组长度表示
int i = 0; int j = row * col -1;
while(i<= j){//注意相等情况,当取一个数的时候
mid = i + (j-i)/2;
int l = mid /col;
int r = mid %col;
if(matix[mid]==target){
return ture;
}else if(matix[mid] <target){
i = mid + 1;
}else{
j = mid -1;
}
}
return false;
}
2题目;寻找一个数最近的数的下标 ;
l m t r
****************************t*******
l m t r
*************t*******
l t m r
****t*******
l m r
*t*
lr
T* //提前停下来,
targer==4 index l = 2 r = 3
// e.g int a[5] = {1 , 2 ,3 ,8 ,9}
int binarySearch(int a[] ,int left ,int right ,int target){
int mid ;//不要重复定义
while(left < right -1){
mid = left + (right - left)/2;
if(arr[mid]==targer){ // 不需要满足条件
return mid ;
} else if(arr[mid]<targer){
left = mid ; //left = mid +1 错误。因为如果正好是那个最近接那个容易跳过去
}else{
right = mid;
}
}
}
post processing
if(abs(arr[left] - targer ) <abs(arr[right] - targer){//判断哪个更加接近
return left;
}else {
return right;
}
3题目;e.g int arr[]={2,5,5,5,5,5,5,,5,5,5,5,} 找出最左边的 targer ;
if targer = 5 return 1 返回下标 if targer = 10 retrun -1;
当l和r相邻的时候。跳出循环,在判断哪个是最左的
int BinarySearch(int arr[] ,int target){
int mid ;
while(left < right -1){
mid = left +(right - left)/2;
if(arr[mid]==target){
right = mid; //当题是最右边的时候 left=mid
}else if(arr[mid]<target){
left = mid ;mid+1也可以,正好是他
}else {
right = mid; //mid -1
}
}
}
if(arr[left] ==targer){//取出数值 //righ 返回也是right
return left;
}else{
return right ;
}
//求出最近的那个数的最k的数字连起来的
List<Integer> list = new ArrayList<>();
if (Math.abs(arr[left] - target) < Math.abs(arr[right] - target)) {
left--;
while (left > 0 && right < arr.length && k > 0) {
list.add(arr[left]);
list.add(arr[right]);
k -= 2;
if (k == 1) {
if (arr[left] < arr[right]) {
left--;
list.add(arr[left]);
} else {
right++;
list.add(arr[right]);
}
}
}
return list;
} else {
right++;
while (left > 0 && right < arr.length && k > 0) {
list.add(arr[left]);
list.add(arr[right]);
k -= 2;
if (k == 1) {
if (left < right) {
left--;
list.add(arr[left]);
} else {
right--;
list.add(arr[right]);
}
}
}
return list;
}
byte 和Byte详解
- :byte和Byte详解
byte是java的基本数据类型,存储整型数据,占据1个字节(8 bits),能够存储的数据范围是-128~+127。
Byte是java.lang中的一个类,目的是为基本数据类型byte进行封装。
- :二者关系:
Byte是byte的包装类,就如同Integer和int的关系,
一般情况包装类用于泛型或提供静态方法,用于基本类型或字符串之间转换,建议尽量不要用包装类和基本类型之间运算,因为这样运算效率会很差的
Map相关
Map是java中的接口,Map.Entry是Map的一个内部接口。
Map提供了一些常用方法,如keySet()、entrySet()等方法,keySet()方法返回值是Map中key值的集合;entrySet()的返回值也是返回一个Set集合,此集合的类型为Map.Entry。
Map.Entry是Map声明的一个内部接口,此接口为泛型,定义为Entry<K,V>。它表示Map中的一个实体(一个key-value对)。接口中有getKey(),getValue方法。
下面是遍历Map的四种方法:
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("1", "value1");
map.put("2", "value2");
map.put("3", "value3");
//第一种:普遍使用,二次取值
System.out.println("通过Map.keySet遍历key和value:");
for (String key : map.keySet()) {
System.out.println("key= "+ key + " and value= " + map.get(key));
}
//第二种
System.out.println("通过Map.entrySet使用iterator遍历key和value:");
Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
//第三种:推荐,尤其是容量大时
System.out.println("通过Map.entrySet遍历key和value");
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
//第四种
System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
for (String v : map.values()) {
System.out.println("value= " + v);
}
}
一、整理:
看到array,就要想到角标。
看到link,就要想到first,last。
看到hash,就要想到hashCode,equals.
看到tree,就要想到两个接口。Comparable,Comparator。
二、Map与Collection在集合框架中属并列存在
1.Map存储的是键值对
2.Map存储元素使用put方法,Collection使用add方法
3.Map集合没有直接取出元素的方法,而是先转成Set集合,在通过迭代获取元素
4.Map集合中键要保证唯一性
也就是Collection是单列集合, Map 是双列集合。
总结:
- Map一次存一对元素, Collection 一次存一个。Map 的键不能重复,保证唯一。
- Map 一次存入一对元素,是以键值对的形式存在.键与值存在映射关系.一定要保证键的唯一性.
三、Map中常见方法:
1、添加:
1、V put(K key, V value) (可以相同的key值,但是添加的value值会覆
盖前面的,返回值是前一个,如果没有就返回null)
2、putAll(Map<? extends K,? extends V> m) 从指定映射中将所有映射关
系复制到此映射中(可选操作)。
2、删除
1、remove() 删除关联对象,指定key对象
2、clear() 清空集合对象
3、获取
1:value get(key); 可以用于判断键是否存在的情况。当指定的键不存在的时候,返
回的是null。
4、判断:
1、boolean isEmpty() 长度为0返回true否则false
2、boolean containsKey(Object key) 判断集合中是否包含指定的key
3、boolean containsValue(Object value) 判断集合中是否包含指定的value
5、长度:
Int size()
四、遍历Map的方式:
1、将map 集合中所有的键取出存入set集合。
Set
2、 values() ,获取所有的值.
Collection
3、 Map.Entry对象 推荐使用 重点
Set<Map.Entry<k,v>> entrySet() 将map 集合中的键值映射关系打包成一个对象。
Map.Entry对象通过Map.Entry 对象的getKey,getValue获取其键和值。
第一种方式:使用keySet
将Map转成Set集合(keySet()),通过Set的迭代器取出Set集合中的每一个元素(Iterator)就是Map集合中的所有的键,再通过get方法获取键对应的值。
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Demo1 {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "aaaa");
map.put(2, "bbbb");
map.put(3, "cccc");
System.out.println(map);
//
// 获取方法:
// 第一种方式: 使用keySet
// 需要分别获取key和value,没有面向对象的思想
// Set<K> keySet() 返回所有的key对象的Set集合
Set<Integer> ks = map.keySet();
Iterator<Integer> it = ks.iterator();
while (it.hasNext()) {
Integer key = it.next();
String value = map.get(key);
System.out.println("key=" + key + " value=" + value);
}
}
}
第二种方式: 通过values 获取所有值,不能获取到key对象
1 public static void main(String[] args) {
2 Map<Integer, String> map = new HashMap<Integer, String>();
3 map.put(1, "aaaa");
4 map.put(2, "bbbb");
5 map.put(3, "cccc");
6 System.out.println(map);
7 // 第二种方式:
8 // 通过values 获取所有值,不能获取到key对象
9 // Collection<V> values()10
11 Collection<String> vs = map.values();
12 Iterator<String> it = vs.iterator();
13 while (it.hasNext()) {
14 String value = it.next();
15 System.out.println(" value=" + value);
16 }
17 }
第三种方式: Map.Entry
public static interface Map.Entry<K,V> 通过Map中的entrySet()方法获取存放Map.Entry<K,V>对象的Set集合。
Set<Map.Entry<K,V>> entrySet() 面向对象的思想将map集合中的键和值映射关系打包为一个对象,就是Map.Entry,将该对象存入Set集合,Map.Entry是一个对象,那么该对象具备的getKey,getValue获得键和值。
1 public static void main(String[] args) {
2 Map<Integer, String> map = new HashMap<Integer, String>();
3 map.put(1, "aaaa");
4 map.put(2, "bbbb");
5 map.put(3, "cccc");
6 System.out.println(map);
7 // 第三种方式: Map.Entry对象 推荐使用 重点
8 // Set<Map.Entry<K,V>> entrySet()
9
10
11 // 返回的Map.Entry对象的Set集合 Map.Entry包含了key和value对象12 Set<Map.Entry<Integer, String>> es = map.entrySet();
13
14 Iterator<Map.Entry<Integer, String>> it = es.iterator();
15
16 while (it.hasNext()) {
17
18 // 返回的是封装了key和value对象的Map.Entry对象19 Map.Entry<Integer, String> en = it.next();
20
21 // 获取Map.Entry对象中封装的key和value对象22 Integer key = en.getKey();
23 String value = en.getValue();
24
25 System.out.println("key=" + key + " value=" + value);
26 }
27 }