LeetCode习题集 有些题可能直接略过了,整理一下之前刷leetcode

701. 二叉搜索树中的插入操作

给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 保证原始二叉搜索树中不存在新值。

注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回任意有效的结果。

例如,

给定二叉搜索树:

    4
   / \
  2   7
 / \
1   3

和 插入的值: 5 你可以返回这个二叉搜索树:

     4
   /   \
  2     7
 / \   /
1   3 5

或者这个树也是有效的:

     5
   /   \
  2     7
 / \   
1   3
     \
      4
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
     public TreeNode insertIntoBST(TreeNode root, int val) {
        if(root == null)return new TreeNode(val);
        else if(root.val > val){
            root.left = insertIntoBST(root.left, val);
        }else if(root.val < val){
            root.right = insertIntoBST(root.right, val);
        }
        return root;
    }
}

703. 数据流中的第K大元素

设计一个找到数据流中第K大元素的类(class)。注意是排序后的第K大元素,不是第K个不同的元素。

你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器,它包含数据流中的初始元素。每次调用 KthLargest.add,返回当前数据流中第K大的元素。

示例:

int k = 3;
int[] arr = [4,5,8,2];
KthLargest kthLargest = new KthLargest(3, arr);
kthLargest.add(3);   // returns 4
kthLargest.add(5);   // returns 5
kthLargest.add(10);  // returns 5
kthLargest.add(9);   // returns 8
kthLargest.add(4);   // returns 8

说明: 你可以假设 nums 的长度≥ k-1 且k ≥ 1。

class KthLargest {

  private PriorityQueue<Integer> queue;
    
    private int kth;
    
    public KthLargest(int k, int[] nums) {
        kth = k;
        queue = new PriorityQueue<>(k);
        for(int x : nums)
            add(x);
    }
    
    public int add(int val) {
        if(queue.size() < kth) {
            queue.add(val);
            return queue.peek();
        }
        if(queue.peek() < val) {
            queue.remove();
            queue.add(val);
        }
        return queue.peek();
    }
}

/**
 * Your KthLargest object will be instantiated and called as such:
 * KthLargest obj = new KthLargest(k, nums);
 * int param_1 = obj.add(val);
 */

704. 二分查找

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

示例 1:

输入: nums = [-1,0,3,5,9,12], target = 9 输出: 4 解释: 9 出现在 nums 中并且下标为 4 示例 2:

输入: nums = [-1,0,3,5,9,12], target = 2 输出: -1 解释: 2 不存在 nums 中因此返回 -1

提示:

你可以假设 nums 中的所有元素是不重复的。 n 将在 [1, 10000]之间。 nums 的每个元素都将在 [-9999, 9999]之间。

PS: 求二分一般都用(right - left) / 2 + left; 主要原因是防止right+left超出int的范围

class Solution {
      public int search(int[] nums, int target) {

        int left = 0;
        int right = nums.length - 1;

        while (left <= right) {

            if (left == right) {
                if (nums[left] == target) {
                    return left;
                } else {
                    return -1;
                }
            }
            int cur = (right - left) / 2 + left;
            if (nums[cur] == target) {
                return cur;
            } else if (nums[cur] > target) {
                right = cur - 1;
            } else {
                left = cur + 1;
            }
        }

        return -1;
    }
}

705. 设计哈希集合

不使用任何内建的哈希表库设计一个哈希集合

具体地说,你的设计应该包含以下的功能

add(value):向哈希集合中插入一个值。 contains(value) :返回哈希集合中是否存在这个值。 remove(value):将给定值从哈希集合中删除。如果哈希集合中没有这个值,什么也不做。

示例:

MyHashSet hashSet = new MyHashSet();
hashSet.add(1);         
hashSet.add(2);         
hashSet.contains(1);    // 返回 true
hashSet.contains(3);    // 返回 false (未找到)
hashSet.add(2);          
hashSet.contains(2);    // 返回 true
hashSet.remove(2);          
hashSet.contains(2);    // 返回  false (已经被删除)

注意:

所有的值都在 [0, 1000000]的范围内。 操作的总数目在[1, 10000]范围内。 不要使用内建的哈希集合库。

class MyHashSet {

   boolean[] flag;

    /** Initialize your data structure here. */
    public MyHashSet() {
        flag=new boolean[1000001];
    }
    
    public void add(int key) {
        flag[key]=true;
    }
    
    public void remove(int key) {
        flag[key]=false;
    }
    
    /** Returns true if this set contains the specified element */
    public boolean contains(int key) {
        return flag[key];
    }
}

/**
 * Your MyHashSet object will be instantiated and called as such:
 * MyHashSet obj = new MyHashSet();
 * obj.add(key);
 * obj.remove(key);
 * boolean param_3 = obj.contains(key);
 */

706. 设计哈希映射

不使用任何内建的哈希表库设计一个哈希映射

具体地说,你的设计应该包含以下的功能

put(key, value):向哈希映射中插入(键,值)的数值对。如果键对应的值已经存在,更新这个值。
get(key):返回给定的键所对应的值,如果映射中不包含这个键,返回-1。
remove(key):如果映射中存在这个键,删除这个数值对。

示例:

MyHashMap hashMap = new MyHashMap();
hashMap.put(1, 1);          
hashMap.put(2, 2);         
hashMap.get(1);            // 返回 1
hashMap.get(3);            // 返回 -1 (未找到)
hashMap.put(2, 1);         // 更新已有的值
hashMap.get(2);            // 返回 1 
hashMap.remove(2);         // 删除键为2的数据
hashMap.get(2);            // 返回 -1 (未找到) 

注意:

所有的值都在 [0, 1000000]的范围内。 操作的总数目在[1, 10000]范围内。 不要使用内建的哈希库。

class MyHashMap {
  /** Initialize your data structure here. */
        class Entry {
            int key;
            int value;
            Entry next;
            Entry(int key, int value) {
                this.key = key;
                this.value = value;
            }
        }
        int cap = 200000;
        Entry [] arr = new Entry[cap];
        public MyHashMap() {
        }

        /** value will always be non-negative. */
        public void put(int key, int value) {
            if(arr[key % cap] != null) {
                boolean isFound = false;
                Entry entry = arr[key % cap], last = null;
                while(entry != null) {
                    last = entry;
                    if(entry.key == key) {
                        entry.value = value;
                        isFound = true;
                        break;
                    }
                    entry = entry.next;
                }
                if(!isFound) {
                    last.next = new Entry(key, value);
                }
            } else {
                arr[key % cap] = new Entry(key, value);
            }
        }

        /** Returns the value to which the specified key is mapped, or -1 if this map contains no mapping for the key */
        public int get(int key) {
            Entry entry = arr[key % cap];
            while(entry != null) {
                if(entry.key == key) {
                    return entry.value;
                }
                entry = entry.next;
            }
            return -1;
        }

        /** Removes the mapping of the specified value key if this map contains a mapping for the key */
        public void remove(int key) {
            Entry entry = arr[key % cap], prev = null;
            while(entry != null) {
                if(entry.key == key) {
                    if (prev == null) {
                        arr[key % cap] = entry.next;
                    } else {
                        prev.next = entry.next;
                    }
                    break;
                }
                prev = entry;
                entry = entry.next;
            }
        }
}

/**
 * Your MyHashMap object will be instantiated and called as such:
 * MyHashMap obj = new MyHashMap();
 * obj.put(key,value);
 * int param_2 = obj.get(key);
 * obj.remove(key);
 */

707. 设计链表

设计链表的实现。您可以选择使用单链表或双链表。单链表中的节点应该具有两个属性:val 和 next。val 是当前节点的值,next 是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性 prev 以指示链表中的上一个节点。假设链表中的所有节点都是 0-index 的。

在链表类中实现这些功能:

get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。 addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。 addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。 addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。 deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。

示例:

MyLinkedList linkedList = new MyLinkedList();
linkedList.addAtHead(1);
linkedList.addAtTail(3);
linkedList.addAtIndex(1,2);   //链表变为1-> 2-> 3
linkedList.get(1);            //返回2
linkedList.deleteAtIndex(1);  //现在链表是1-> 3
linkedList.get(1);            //返回3

提示:

所有val值都在 [1, 1000] 之内。 操作次数将在 [1, 1000] 之内。 请不要使用内置的 LinkedList 库。

class MyLinkedList {

    private class ListNode {
        int val;
        ListNode prev;
        ListNode next;
        ListNode(int x) {val = x;}
    }

    private ListNode head;
    private ListNode tail;
    int size; 
    public MyLinkedList() {
        head = new ListNode(0);
        tail = new ListNode(0);
        head.next = tail;
        tail.prev = head;
    }
    
     
    public int get(int index) {
        if (index >= size || index < 0) return -1;

        ListNode curr = head;
        if (index * 2 < size - 1) {
            for (int i = 0; i <= index; i++) curr = curr.next;
        } else {
            curr = tail;
            for (int i = 0; i < size - index; i++) curr = curr.prev;
        }
        return curr.val;
    }
    
   
    public void addAtHead(int val) {
        ListNode node = new ListNode(val);
        ListNode next = head.next;
        node.next = next;
        node.prev = head;
        next.prev = node;
        head.next = node;
        size++;
    }
     
    public void addAtTail(int val) {
        ListNode node = new ListNode(val);
        ListNode prev = tail.prev;
        node.next = tail;
        node.prev = prev;
        prev.next = node;
        tail.prev = node;
        size++;
    }
     
    public void addAtIndex(int index, int val) {
        if (index > size || index < 0) return;

        ListNode prev, curr;
        if (index * 2 < size) {
            prev = head;
            for(int i = 0; i < index; i++) prev = prev.next;
            curr = prev.next;
        } else {
            curr = tail;
            for (int i = 0; i < size - index; i++) curr = curr.prev;
            prev = curr.prev;
        }

        ListNode node = new ListNode(val);
        node.prev = prev;
        node.next = curr;
        prev.next = node;
        curr.prev = node;
        ++size;
    }
     
    public void deleteAtIndex(int index) {
        if (index >= size || index < 0) return;

        ListNode prev, next;
        if (index * 2 < size) {
            prev = head;
            for(int i = 0; i < index; i++) prev = prev.next;
            next = prev.next.next;
        } else {
            next = tail;
            for (int i = 0; i < size - index - 1; i++) next = next.prev;
            prev = next.prev.prev;
        }

        prev.next = next;
        next.prev = prev;

        size--;
    }
}

/**
 * Your MyLinkedList object will be instantiated and called as such:
 * MyLinkedList obj = new MyLinkedList();
 * int param_1 = obj.get(index);
 * obj.addAtHead(val);
 * obj.addAtTail(val);
 * obj.addAtIndex(index,val);
 * obj.deleteAtIndex(index);
 */

709. 转换成小写字母

实现函数 ToLowerCase(),该函数接收一个字符串参数 str,并将该字符串中的大写字母转换成小写字母,之后返回新的字符串。

示例 1:

输入: "Hello" 输出: "hello" 示例 2:

输入: "here" 输出: "here" 示例 3:

输入: "LOVELY" 输出: "lovely"

class Solution {
      public String toLowerCase(String str) {
        char[] arr = str.toCharArray();

        StringBuilder sb = new StringBuilder();
        for (char c : arr) { 
            if (c >= 'A' && c <= 'Z') { 
                c = (char) ((int)c + 32);
            }

            sb.append(c);
        }

        return sb.toString();
    }
}

710. 黑名单中的随机数

给定一个包含 [0,n ) 中独特的整数的黑名单 B,写一个函数从 [ 0,n ) 中返回一个不在 B 中的随机整数。

对它进行优化使其尽量少调用系统方法 Math.random() 。

提示:

1 <= N <= 1000000000 0 <= B.length < min(100000, N) [0, N) 不包含 N,详细参见 interval notation 。 示例 1:

输入: 
["Solution","pick","pick","pick"]
[[1,[]],[],[],[]]
输出: [null,0,0,0]

示例 2:

输入: 
["Solution","pick","pick","pick"]
[[2,[]],[],[],[]]
输出: [null,1,1,1]

示例 3:

输入: 
["Solution","pick","pick","pick"]
[[3,[1]],[],[],[]]
Output: [null,0,0,2]

示例 4:

输入: 
["Solution","pick","pick","pick"]
[[4,[2]],[],[],[]]
输出: [null,1,3,1]

输入语法说明:

输入是两个列表:调用成员函数名和调用的参数。Solution的构造函数有两个参数,N 和黑名单 B。pick 没有参数,输入参数是一个列表,即使参数为空,也会输入一个 [] 空列表。



class Solution {

	 int n=0, cnt=0;
    HashSet<Integer> h=null;
    boolean [] set=null;
    int [] candidates=null;
    public Solution(int N, int[] blacklist) {

      n=N;
      
      int L=blacklist.length, i=0;
      if( N>20000)
      {
        h=new HashSet<Integer>();
      
        while( i<L )
        {
          h.add(blacklist[i]);	
          i++;	
        }
        return;
      }
      
      set=new boolean [N];
      while( i<L )
      {
    	set[blacklist[i]]=true;  
        i++;	  
      }
      i=0;
      
      cnt=N-L;
      candidates=new int [cnt];
      int j=0;
      while( i<N )
      {
    	if( set[i]==false )
    	{
    	  candidates[j]=i;
    	  j++;
    	}
        i++;	  
      }
    }
    
    public int pick() {
    	
      if( n>20000 )
      {
    	int oup=(int)(Math.random()*n);
          
        while( h.contains(oup) )
          oup=(int)(Math.random()*n);
          
        return oup;  
      }     
    	
      return candidates[(int)(Math.random()*cnt)];      
    }
}

/**
 * Your Solution object will be instantiated and called as such:
 * Solution obj = new Solution(N, blacklist);
 * int param_1 = obj.pick();
 */