数据结构

链表

  1. 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(str1
null||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

但是,二叉搜索树对哈希表的性能很好:

  1. 二进制搜索树永远不会遇到冲突,这意味着二进制搜索树可以保证在O(log(n))中实现插入,检索和删除,这比线性时间快得多。此外,树所需的空间与输入数据的大小完全相同。
  2. 您无需事先知道输入大小。
  3. 对树中的所有元素进行排序,以使有序遍历花费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详解

  1. :byte和Byte详解
    byte是java的基本数据类型,存储整型数据,占据1个字节(8 bits),能够存储的数据范围是-128~+127。

Byte是java.lang中的一个类,目的是为基本数据类型byte进行封装。

  1. :二者关系:
    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 keySet() 返回所有的key对象的Set集合,再通过get方法获取键对应的值。
2、 values() ,获取所有的值.
Collection values()不能获取到key对象
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 }
posted @ 2020-09-21 12:02  杰的博客#  阅读(152)  评论(0编辑  收藏  举报