算法

//反转链表
//输入一个链表,反转链表后,输出新链表的表头。
public class Solution {
public ListNode ReverseList(ListNode head) {
//建立一个新的带假头的空链表;
ListNode dummy = new ListNode(0);
//遍历旧链表,依次取出旧链表中的每个结点;
while(head != null){
// 把旧链表中的结点取出来,采用头部插入的方法添加到新链表中
ListNode temp = head.next;

        head.next = dummy.next;
        dummy.next = head;
        head = temp;
    }
    // 返回新链表的头,注意,不要返回dummy!!
    return dummy.next;
}

}
function ReverseList(pHead)
{
// write code here
let dummy = new ListNode(0);
while(pHead != null){
let temp = pHead.next;

    pHead.next = dummy.next;
    dummy.next = pHead;
    pHead = temp;
}
return dummy.next;

}

//链表中的节点每k个一组翻转
// 题目描述
// 将给出的链表中的节点每\ k k 个一组翻转,返回翻转后的链表
// 如果链表中的节点数不是\ k k 的倍数,将最后剩下的节点保持原样
// 你不能更改节点中的值,只能更改节点本身。
// 要求空间复杂度 \ O(1) O(1)
// 例如:
// 给定的链表是1\to2\to3\to4\to51→2→3→4→5
// 对于 \ k = 2 k=2, 你应该返回 2\to 1\to 4\to 3\to 52→1→4→3→5
// 对于 \ k = 3 k=3, 你应该返回 3\to2 \to1 \to 4\to 53→2→1→4→5

public class Solution {
/**
*
* @param head ListNode类
* @param k int整型
* @return ListNode类
*/
public ListNode reverseKGroup (ListNode head, int k) {
ListNode virtualRoot = new ListNode(0);
virtualRoot.next = head;
ListNode pre = virtualRoot;
ListNode temp, start = pre.next;

    int count = 0;
    while (head != null) {
        count++;
        head = head.next;
    }
    for (int i = 0; i < count / k; i++) {
        for (int j = 1; j < k; j++) {
            temp = start.next;
            start.next = temp.next;
            temp.next = pre.next;
            pre.next = temp;
        }
        pre = start;
        start = start.next;
    }
    return virtualRoot.next;
}

}

class Solution{
private ListNode tmp = new ListNode(0);
private ListNode tmpTail = tmp;
private int len =0;

  private ListNode ans = new ListNode(0);
  private ListNode ansTail = ans;
  
  private ListNode reverse(ListNode head){
      ListNode dummy = new ListNode(0);
      ListNode p = head;
      while(p != null){
          ListNode back = p.next;
          p.next = dummy.next;
          dummy.next = p;
          p = back;
      }
      return dummy.next;
  }
  private void append(ListNode p,int k){
      //将进来的结点添加到tmp链表中
      //如果tmp链表中的结点个数==k
      //那么就需要把tmp链表进行反转,然后再加入到ans链表中
      tmpTail.next = p;
      tmpTail = tmpTail.next;
      len++;
      if(len == k){
         // 如果长为k,那么就需要进行一下翻转。
        // 这里记录下翻转之后的
        ListNode tail = tmp.next;
        ListNode head = reverse(tmp.next);

        // 反转后的链表是[head, tail]
        // 那么需要将这个链表添加到[ans, ansTail]里面
        ansTail.next = head;
        ansTail = tail;

        // 然后再把tmp链表清空
       len =0;
       tmp.next = null;
       tmpTail = tmp;
      }
  }
  public ListNode reverseKGroup(ListNode head,int k){
    ListNode p = head;
    while (p != null) {
        ListNode back = p.next;

        p.next = null;
        append(p, k);

        p = back;
    }

    if (len > 0) {
        ansTail.next = tmp.next;
        ansTail = tmpTail;
    }

    ansTail.next = null;

    return ans.next;
  }

}

function reverseKGroup( head , k ) {
if(!head) return head;
let a = head;
let b = head;
for(let i=0;i<k;i++){
// 不满足 K 个一组,直接返回头结点
if(!b) return head;
b = b.next;
}
// 新的头结点
let newHead = reverseLink(a, b);
// 此时翻转后,a是尾节点了,与子问题的头结点相接即可
a.next = reverseKGroup(b, k);
// 返回头结点
return newHead;
}
// [head, tail) 翻转
function reverseLink(head,tail){
let cur = head;
let pre = null;
let next = cur;
while(cur !== tail){
next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
module.exports = {
reverseKGroup : reverseKGroup
};

public class Solution {
/**
*
* @param head ListNode类
* @param k int整型
* @return ListNode类
*/
public ListNode reverseKGroup (ListNode head, int k) {
ListNode virtualRoot = new ListNode(0);
virtualRoot.next = head;
ListNode pre = virtualRoot;
ListNode temp, start = pre.next;

    int count = 0;
    while (head != null) {
        count++;
        head = head.next;
    }
    for (int i = 0; i < count / k; i++) {
        for (int j = 1; j < k; j++) {
            temp = start.next;
            start.next = temp.next;
            temp.next = pre.next;
            pre.next = temp;
        }
        pre = start;
        start = start.next;
    }
    return virtualRoot.next;
}

}

//3.判断链表中是否有环
// 题目描述
// 判断给定的链表中是否有环。如果有环则返回true,否则返回false。
// 你能给出空间复杂度的解法么?
public class Solution {
public boolean hasCycle(ListNode head) {
if(head == null){
return false;
}
//快慢两个指针
ListNode slow = head;
ListNode fast = head;
while(fast != null && fast.next != null){
//慢指针每次走一步
slow = slow.next;
//快指针每次走两步
fast = fast.next.next;
//如果相遇,说明有环,直接返回true
if(slow == fast){
return true;
}
}
//否则就是没环
return false;
}
}

function hasCycle( head ) {
// write code here
let slow = head;
let fast = head;
while(fast != null && fast.next !=null){
slow = slow.next;
fast = fast.next.next;
if(slow == fast){
return true;
}
}
return false;
}
module.exports = {
hasCycle : hasCycle
};
//4.最小的k个数
// 题目描述
// 给定一个数组,找出其中最小的K个数。例如数组元素是4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。如果K>数组的长度,那么返回一个空的数组
// [4,5,1,6,2,7,3,8],4
// [1,2,3,4]
import java.util.;
public class Solution {
public ArrayList GetLeastNumbers_Solution(int [] input, int k) {
int f=0;
ArrayList s = new ArrayList();
if(k>input.length){
return s;
}
for(int i = 0;i<k;i++){
for(int j =i;j<input.length;j++){
if(input[i] > input[j]){
f = input[i];
input[i] = input[j];
input[j] = f;
}
}
s.add(input[i]);
}
return s;
}
}
//java优先队列
import java.util.
;
public class Solution {
public ArrayList GetLeastNumbers_Solution(int [] input, int k) {
ArrayList res = new ArrayList<>();
int len = input.length;
if(len < k || k == 0){
return res;
}
// java优先队列默认是小顶堆,我们要设置为大顶堆
// 这里用的lambda表达式实现比较器接口
Queue pq = new PriorityQueue<>(k,(a, b)->(b-a));
for(int i = 0; i < len; i++){
// 队列没满时,需要加满
if(pq.size() < k){
pq.add(input[i]);
}else{
// 队列满了即i>=k时,需要开始判断,当前值小于堆顶时需要加入队列
if(input[i] < pq.peek()){
pq.poll();
pq.add(input[i]);
}
}
}
res.addAll(pq);
return res;
}
}

function GetLeastNumbers_Solution(input, k)
{
const res =[];
// write code here
if(k>input.length || k == 0){
return res;
}
for(let i = 0; i<k;i++){
for(let j = i;j<input.length;j++){
if(input[i] > input[j]){
const temp = input[i];
input[i] = input[j];
input[j] = temp;
}
}
res.push(input[i]);
}
return res;
}
//5.设计LRU缓存结构
// 题目描述
// 设计LRU缓存结构,该结构在构造时确定大小,假设大小为K,并有如下两个功能
// set(key, value):将记录(key, value)插入该结构
// get(key):返回key对应的value值
// [要求]
// set和get方法的时间复杂度为O(1)
// 某个key的set或get操作一旦发生,认为这个key的记录成了最常使用的。
// 当缓存的大小超过K时,移除最不经常使用的记录,即set或get最久远的。
// 若opt=1,接下来两个整数x, y,表示set(x, y)
// 若opt=2,接下来一个整数x,表示get(x),若x未出现过或已被移除,则返回-1
// 对于每个操作2,输出一个答案
// 示例1

// [[1,1,1],[1,2,2],[1,3,2],[2,1],[1,4,4],[2,2]],3

// [1,-1]

import java.util.*;

public class Solution {
static class Node{
int key , value;
Node prev,next;
public Node(int key , int value){
this.key = key;
this.value = value;
}
}
private Map<Integer,Node> map = new HashMap<>();
private Node head = new Node(-1,-1);
private Node tail = new Node(-1,-1);
private int k;
public int[] LRU (int[][] operators, int k) {
// write code here
this.k = k;
head.next = tail;
tail.prev = head;
int len =(int) Arrays.stream(operators).filter(x->x[0] == 2).count();
int[] ans = new int[len];
int cnt = 0;
for(int i=0;i < operators.length ;i++){
if(operators[i][0] == 1){
set(operators[i][1],operators[i][2]);
}else{
ans[cnt++] = get(operators[i][1]);
}
}
return ans;
}
public void set(int key,int value){
if(get(key) > -1){
map.get(key).value = value;
}else{
if(map.size() == k ){
int rk = tail.prev.key;
tail.prev.prev.next = tail;
tail.prev = tail.prev.prev;
map.remove(rk);
}
Node node = new Node(key,value);
map.put(key,node);
removeToHead(node);
}
}
public int get(int key){
if(map.containsKey(key)){
Node node = map.get(key);
node.prev.next = node.next;
node.next.prev = node.prev;

        removeToHead(node);
        return node.value;
    }
    return -1;
}
public void removeToHead(Node node){
    node.next = head.next;
    head.next.prev = node;
    head.next = node;
    node.prev = head;
}

}

import java.util.*;

public class Solution {
/**
* lru design
* @param operators int整型二维数组 the ops
* @param k int整型 the k
* @return int整型一维数组
*/
public int[] LRU (int[][] operators, int k) {
Map<Integer,Integer> map = new LinkedHashMap<>();
List list = new LinkedList<>();
for(int[] operator:operators){
int key = operator[1];
switch(operator[0]){
case 1:
int value = operator[2];
if(map.size()<k){
map.put(key,value);
}else{
Iterator it = map.keySet().iterator();
map.remove(it.next());
map.put(key,value);
}
break;
case 2:
if(map.containsKey(key)){
int val = map.get(key);
list.add(val);
map.remove(key);
map.put(key,val);
}else{
list.add(-1);
}
break;
default:
}
}
int[] res = new int[list.size()];
int i=0;
for(int val:list){
res[i++] = val;
}
return res;
}
}

//6.括号序列
// 题目描述
// 给出一个仅包含字符’(’,’)’,’{’,’}’,’[‘和’]’,的字符串,判断给出的字符串是否是合法的括号序列
// 括号必须以正确的顺序关闭,"()“和”()[]{}“都是合法的括号序列,但”(]“和”([)]"不合法。
public class Solution {
/**
*
* @param s string字符串
* @return bool布尔型
*/
public boolean isValid (String s) {
// write code here
Stack stack = new Stack();
for(int i=0;i<s.length();i++){
if(stack.empty()){
stack.push(s.charAt(i));
continue;
}
if(s.charAt(i) == ‘)’ && stack.peek() == ‘(’){
stack.pop();
}else if(s.charAt(i) == ‘}’ && stack.peek() == ‘{’){
stack.pop();
}else if(s.charAt(i)== ‘]’ && stack.peek() == ‘[’){
stack.pop();
}else{
stack.push(s.charAt(i));
}
}
return stack.empty();
}

function isValid( s ) {
let stack = [];
let pair = {
‘{’:’}’,
‘(’:’)’,
‘[’:’]’
};
for(let i=0;i<s.length;i++){
if(pair[s[i]]){
stack.push(s[i]);
}else if(pair[stack[stack.length-1]] !== s[i]){
return false;
}else{
stack.pop()
}
}
return stack.length<=0;
}
module.exports = {
isValid : isValid
};
//7.合并两有序数组
// 题目描述
// 给出两个有序的整数数组A和 B,请将数组 B合并到数组 A中,变成一个有序的数组
// 注意:
// 可以假设A 数组有足够的空间存放 数组的元素, A和 B中初始的元素数目分别为m 和n
public class Solution {
public void merge(int A[], int m, int B[], int n) {
//因为题目明确说了A数组足够大,所以直接在A数组操作
int i = m-1;
int j = n-1;
int index = m+n -1;//AB合并后最后一个元素所在位置
while(i>=0&&j>=0){//AB合并,谁大就先放谁
A[index–] =A[i]>B[j]?A[i–]:B[j–];
}
while(j >=0){//如果B没有遍历完,那么之间丢在A数组里面
A[index–] = B[j–];
}
}
}
/**
*

  • @param A int整型一维数组
  • @param B int整型一维数组
  • @return void
    /
    function merge( A, m, B, n ) {
    // write code here
    let i =m-1;
    let j = n-1;
    let index= m+n-1;
    while(i>=0 && j>=0){
    A[index–] = A[i]>B[j]?A[i–]:B[j–];
    }
    while(j>=0){
    A[index–] = B[j–];
    }
    }
    module.exports = {
    merge : merge
    };
    //8.实现二叉树先序,中序和后序遍历
    // 题目描述
    // 分别按照二叉树先序,中序和后序打印所有的节点。
    // 示例1
    // {1,2,3}
    // [[1,2,3],[2,1,3],[2,3,1]]
    public class Solution {
    /
    *
    *
    • @param root TreeNode类 the root of binary tree

    • @return int整型二维数组
      */
      public int[][] threeOrders (TreeNode root) {
      // write code here
      List list1 = new ArrayList<>();
      List list2 = new ArrayList<>();
      List list3 = new ArrayList<>();
      preOrder(root,list1);
      inOrder(root,lisr2);
      postOrder(root,list3);

      int[][] res = new int[3][list1.size()];
      for(int i=0;i<list1.size();i++){
      res[0][i] = list1.get(i);
      res[1][i] = list2.get(i);
      res[2][i] = list3.get(i);
      }
      return res;
      }
      public static void preOrder(TreeNode root,List list){
      if(root == null) return ;
      list.add(root.val);
      preOrder(root.left,list);
      preOrder(root.right,list);
      }
      public static void inOrder(TreeNode root,List list){
      if(root == null) return ;

      inOrder(root.left,list);
      list.add(root.val);
      inOrder(root.right,list);
      }
      public static void postOrder(TreeNode root,List list){
      if(root == null) return ;

      postOrder(root.left,list);
      postOrder(root.right,list);
      list.add(root.val);
      }
      }
      //9.二叉树的之字形层遍历
      // 题目描述
      // 给定一个二叉树,返回该二叉树的之字形层序遍历,(第一层从左向右,下一层从右向左,一直这样交替)
      // 例如:
      // 给定的二叉树是{3,9,20,#,#,15,7},
      // 该二叉树之字形层序遍历的结果是
      // [
      // [3],
      // [20,9],
      // [15,7]]
      import java.util.*;

/*

  • public class TreeNode {
  • int val = 0;
  • TreeNode left = null;
  • TreeNode right = null;
  • }
    */

public class Solution {
/**
*
* @param root TreeNode类
* @return int整型ArrayList<ArrayList<>>
*/
//这道题目就是层次遍历的变形.按照层次遍历的思想先遍历,如3;9,20;15,7;18,16;
//然后在添加元素的时候把第二行第四行的数据反过来添加到结果中去就可以了
public ArrayList<ArrayList> zigzagLevelOrder (TreeNode root) {
// write code here
ArrayList<ArrayList> result = new ArrayList<ArrayList>();
if(root == null) return result;
ArrayList list = new ArrayList();
list.add(root);
int flag = 1;
while(list.size()>0){
ArrayList newLine = new ArrayList();
ArrayList newList = new ArrayList();
for(int i=0;i<list.size();i++){
//添加新元素到队列中去
if(list.get(i).left != null){
newList.add(list.get(i).left);
}
if(list.get(i).right != null){
newList.add(list.get(i).right);
}
if(flag == 1){
//表示从前往后添加
newLine.add(list.get(i).val);
}else{
//表示从后往前添加
newLine.add(0,list.get(i).val);
}
}
flag = 1-flag;
list = newList;
result.add(newLine);
}
return result;
}
}
function zigzagLevelOrder( root ) {
if(!root) return [];
let queue = [root];
const res = [];
while(queue.length){
let newQueue = [];
res.push([]);
for(let i =0;i<queue.length;i++){
const node = queue[i];
if(res.length%2){
res[res.length-1].push(node.val);
}else{
res[res.length-1].unshift(node.val);
}
if(node.left){
newQueue.push(node.left);
}
if(node.right){
newQueue.push(node.right);
}
}
queue = newQueue;
}
return res;
}

//10.买卖股票的最好时机
// 题目描述
// 假设你有一个数组,其中第\ i i 个元素是股票在第\ i i 天的价格。
// 你有一次买入和卖出的机会。(只有买入了股票以后才能卖出)。请你设计一个算法来计算可以获得的最大收益。
// [1,4,2] 3
import java.util.*;

public class Solution {
/**
*
* @param prices int整型一维数组
* @return int整型
/
public int maxProfit (int[] prices) {
// write code here
int min = prices[0];
int ans =0;
for(int i=0;i<prices.length;i++){
min = Math.min(min,prices[i]);
ans =Math.max(ans,prices[i]-min);
}
return ans;
}
}
import java.util.
;

public class Solution {
/**
*
* @param prices int整型一维数组
* @return int整型
*/
public int maxProfit (int[] prices) {
int N=prices.length;
int DPIhava=Integer.MIN_VALUE;//当前持有股票,初始值为负无穷
int DPIsell=0;//当前未持有股票,初始值为0
for(int i=0;i<N;i++) {
DPIsell=Math.max(DPIsell,DPIhava+prices[i]);//当前天未持股,没有买,或者当天卖掉
DPIhava=Math.max(DPIhava, -prices[i]);//当前天持股,没有买,和当天购买(在持有股票的天数中,必定最便宜)
}
return DPIsell;//最后一天并且没有持股的收益最大值
}
}

import java.util.*;
//10.买卖股票的最好时机
// 题目描述
// 假设你有一个数组,其中第\ i i 个元素是股票在第\ i i 天的价格。
// 你有一次买入和卖出的机会。(只有买入了股票以后才能卖出)。请你设计一个算法来计算可以获得的最大收益。
// [1,4,2] 3

public class Solution {
/**
*
* @param prices int整型一维数组
* @return int整型
*/
public int maxProfit (int[] prices) {
int len = prices.length;
int min = Integer.MIN_VALUE;
int sell = 0;
for(int i =0;i<len;i++){
sell = Math.max(sell,min+prices[i]);
min = Math.max(min,-prices[i]);
}
return sell;
}
}

public class Solution {
/**
*
* @param prices int整型一维数组
* @return int整型
*/
public int maxProfit (int[] prices) {
// write code here
if(null == prices || prices.length == 0){
return 0;
}
int profit = 0,buy = prices[0];
for(int i=1;i<prices.length;i++){
buy = Math.min(buy,prices[i]);
profit =Math.max(profit,prices[i]-buy);
}
return profit;
}
}

//11.寻找第K大
//题目描述
// 有一个整数数组,请你根据快速排序的思路,找出数组中第K大的数。

// 给定一个整数数组a,同时给定它的大小n和要找的K(K在1到n之间),请返回第K大的数,保证答案存在。

public class Solution {
public int findKth(int[] a, int n, int K) {
// write code here
return findK(a,0,n-1,K);
}
public static int findK(int[] arr,int left,int right,int k){
if(left<=right){
int pivot = partition(arr,left,right);
if(pivot == k-1){
return arr[pivot];
}else if(pivot < k-1){
return findK(arr,pivot+1,right,k);
}else{
return findK(arr,left,pivot-1,k);
}
}
return -1;
}
public static int partition(int[] arr,int left,int right){
int pivot =arr[left];
while(left<right){
while(left<right && arr[right]<= pivot){
right–;
}
arr[left] = arr[right];
while(left<right && arr[left]>=pivot){
left++;
}
arr[right] = arr[left];
}
arr[left] = pivot;
return left;
}
// }
// //12.二分查找
// 题目描述
// 请实现有重复数字的升序数组的二分查找
// 给定一个 元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1
// [1,2,4,4,5] 4
// 返回值:2
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 如果目标值存在返回下标,否则返回 -1
* @param nums int整型一维数组
* @param target int整型
* @return int整型
*/
public int search (int[] nums, int target) {
// write code here
int left = 0;
int right = nums.length-1;
int index = -1;
while(left<=right){
int mid = (left+right)>>1;//low+(high-low)/2;
if(nums[mid] == target){
index = mid;
right = mid-1;
}else if(nums[mid] > target){
right = mid-1;
}else{
left = mid+1;
}
}
return index;
}
}

//13.二叉树的镜像
// 题目描述
// 操作给定的二叉树,将其变换为源二叉树的镜像。
// 比如: 源二叉树
// 8
// /
// 6 10
// / \ /
// 5 7 9 11
// 镜像二叉树
// 8
// /
// 10 6
// / \ /
// 11 9 7 5

// 输入
// {8,6,10,5,7,9,11}
// 返回值
// {8,10,6,11,9,7,5}

public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param pRoot TreeNode类
* @return TreeNode类
*/
public TreeNode Mirror (TreeNode pRoot) {
// write code here
if(pRoot == null) return null;
TreeNode lval = Mirror(pRoot.left);
TreeNode rval = Mirror(pRoot.right);
pRoot.left = rval;
pRoot.right = lval;
return pRoot;
}
}

//DFS

public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param pRoot TreeNode类
* @return TreeNode类
*/
public TreeNode Mirror (TreeNode pRoot) {
// write code here
if(pRoot == null) return null;
Stack stack = new Stack<>();
stack.push(pRoot);
while(!stack.empty()){
TreeNode node = stack.pop();

        TreeNode temp  = node.left;
        node.left = node.right;
        node.right = temp;
        
        if(node.left != null){
            stack.push(node.left);
        }
        if(node.right != null){
            stack.push(node.right);
        }
    }
    return pRoot;
}

}

//14.判断一棵二叉树是否为搜索二叉树和完全二叉树
// 题目描述
// 给定一棵二叉树,已经其中没有重复值的节点,请判断该二叉树是否为搜索二叉树和完全二叉树。
// 示例1
// 输入
// {2,1,3}
// 返回值
// [true,true]

public class Solution {

/**
 *
 * @param root TreeNode类 the root
 * @return bool布尔型一维数组
 */
 public boolean[] judgeIt (TreeNode root) {
     return new boolean[]{isSearch(root),isComplete(root)};
}
private boolean isSearch(TreeNode root){
    if(root == null) return true;
    if(root.left != null && root.left.val > root.val){
        return false;
    }
    if(root.right != null && root.right.val < root.val){
        return false;
    }
    return isSearch(root.left)&&isSearch(root.right);
}
private boolean isComplete(TreeNode root){
    if(root == null) return true;
    LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
    queue.add(root);
    while(!queue.isEmpty()){
        TreeNode node = queue.removeFirst();
        if(node != null){
            queue.add(node.left);
            queue.add(node.right);
        }else{
            while(!queue.isEmpty()){
                TreeNode tempNode = queue.removeFirst();
                if(tempNode != null){
                    return false;
                }
            }
        }
    }
     return true;
}

}

//15.最长无重复子串
// 题目描述
// 给定一个数组arr,返回arr的最长无的重复子串的长度(无重复指的是所有数字都不相同)。
// 示例1
// 输入
// [2,3,4,5]
// 返回值
// 4

public class Solution {
/**
*
* @param arr int整型一维数组 the array
* @return int整型
*/
public int maxLength (int[] arr) {
int res = 0,left = -1;
//用来存放窗口存放过的数字
HashMap<Integer,Integer> windows = new HashMap<>();
//窗口不断往右移
for(int right = 0;right<arr.length;right++){
//根据题目,当遇到重复的数字时,缩小左侧窗口
if(windows.containsKey(arr[right])){
//因为我们有可能遇到索引比left原来还小的相同数字
//所以这里要进行比较,目的还是为了缩小左侧窗口,确保窗口内全是不重复的数字
left = Math.max(left,windows.get(arr[right]));
}
//更新窗口内数字的索引
windows.put(arr[right],right);
//right-left是窗口大小
//因为要找最长,所以要进行比较
res =Math.max(res,right-left);
}
return res;
}
}

function maxLength( arr ) {
// write code here
let res = 0;
let left = -1;
let temp = new Map();
for(let right =0;right<arr.length;right++){
if(temp.get(arr[right])){
left = Math.max(left,temp.get(arr[right]));
}
temp.set(arr[right],right);
res = Math.max(res,right-left);
}
return res;
}
module.exports = {
maxLength : maxLength
};

//16.缺失数字
// 题目描述
// 从0,1,2,…,n这n+1个数中选择n个数,组成有序数组,请找出缺失的那个数,要求O(n)尽可能小。
// //输入:[0,1,2,3,4,5,7]
//输出 6
function solve( a ) {
// write code here
let left =0;
let right = a.length;
while(left<right){
const mid = left+Math.floor((right-left)/2);
if(a[mid] === mid){
left = mid+1;
}else if(a[mid]>mid){
right = mid;
}
}
return left;
}
module.exports = {
solve : solve
};

public class Solution {
/**
* 找缺失数字
* @param a int整型一维数组 给定的数字串
* @return int整型
/
public int solve (int[] a) {
int sum = 0;
if(a != null){
int n = a.length;
sum = (n
(n+1))/2;
for(int i =0;i<n;i++){
sum = sum-a[i];
}
return sum;
}
return sum;
}
}

//17.合并有序链表
// 题目描述
// 将两个有序的链表合并为一个新链表,要求新的链表是通过拼接两个链表的节点来生成的,且合并后新链表依然有序。
//输入:{1} ,{2}
//返回值:{1,2}

// 1.新建一个带假头的新链表 dummy,
// 2.然后把 l1,l2中的元素从小到大,依次添加到新生成的链表 dummy中。因此,我们还需要使用到尾部插入法。
// 步骤:
// 第一步:l1,l2 两个指针分别指向 l1,l2链表的表头。
// 第二步:依次取出 l1,l2 两个指针中更小的值加入新链表中。
// 第三步:返回 Cdummy链表假头的 next。
public class Solution {
/**
*
* @param l1 ListNode类
* @param l2 ListNode类
* @return ListNode类
*/
public ListNode mergeTwoLists (ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(0);
ListNode tail = dummy;
while(l1 != null || l2 != null){
if(l2 == null || l1 != null && l1.val<l2.val){
tail.next = l1;
tail = l1;
l1 = l1.next;
}else{
tail.next =l2;
tail = l2;
l2 = l2.next;
}
}
tail.next = null;
return dummy.next;
}
}

//18.合并区间
// 题目描述
// 给出一组区间,请合并所有重叠的区间。
// 请保证合并后的区间按区间起点升序排列。
// 示例1
// 输入
// [[10,30],[20,60],[80,100],[150,180]]
// 返回值
// [[10,60],[80,100],[150,180]]
public class Solution {
public ArrayList merge(ArrayList intervals) {
intervals.sort((a,b)->(a.start-b.start));//按照区间的左端点排序
ArrayList res = new ArrayList();
int i =0,n=intervals.size();
int l,r;
while(i<n){
l = intervals.get(i).start;//用来存储当前区间的左端
r = intervals.get(i).end;//用来存储当前区间的右端
//合并区间
while(i<n-1 && r>= intervals.get(i+1).start){
i++;
r = Math.max(r,intervals.get(i).end);
}
//将当前合并完的区间进行插入
res.add(new Interval(l,r));
i++;
}
return res;
}
}

//19.两数之和
// 题目描述
// 给出一个整数数组,请在数组中找出两个加起来等于目标值的数,
// 你给出的函数twoSum 需要返回这两个数字的下标(index1,index2),需要满足 index1 小于index2.。注意:下标是从1开始的
// 假设给出的数组中只存在唯一解
// 例如:
// 给出的数组为 {20, 70, 110, 150},目标值为90
// 输出 index1=1, index2=2
// 输入
// [3,2,4],6
// 返回值
// [2,3]
import java.util.*;

public class Solution {
/**
*
* @param numbers int整型一维数组
* @param target int整型
* @return int整型一维数组
*/
public int[] twoSum (int[] numbers, int target) {
// write code here
int[] res = {0,0};
HashMap<Integer,Integer> mp = new HashMap<Integer,Integer>();
for(int i=0;i<numbers.length;i++){
mp.put(numbers[i],i);
}
for(int i=0;i<numbers.length;i++){
if(mp.containsKey(target-numbers[i]) && i != mp.get(target-numbers[i])){
res[0] = i+1;
res[1] = mp.get(target-numbers[i]) +1;
return res;
}
}
return res;
}
}

/**
*

  • @param numbers int整型一维数组

  • @param target int整型

  • @return int整型一维数组
    */
    function twoSum( numbers , target ) {
    const map = new Map();
    const len = numbers.length;
    for(let i=0;i<len;i++){
    if(map.has(target-numbers[i])){
    return [map.get(target-numbers[i]) + 1,i + 1]

    }else{
        map.set(numbers[i],i);
    }
    

    }
    }
    module.exports = {
    twoSum : twoSum
    };
    //20.数组中相加和为0的三元组
    // 题目描述
    // 给出一个有n个元素的数组S,S中是否有元素a,b,c满足a+b+c=0?找出数组S中所有满足条件的三元组。
    // 注意:
    // 三元组(a、b、c)中的元素必须按非降序排列。(即a≤b≤c)
    // 解集中不能包含重复的三元组。
    // 例如,给定的数组 S = {-10 0 10 20 -10 -40},解集为(-10, 0, 10) (-10, -10, 20)
    // 输入
    // [-2,0,1,1,2]
    // 返回值
    // [[-2,0,2],[-2,1,1]]
    // 思路:
    // (1)首先对数组进行排序(从小到大)
    // (2)依次取出第 i 个数(i从0开始),并且不重复的选取(跳过重复的数)
    // (3)这样问题就转换为 2 个数求和的问题(可以用双指针解决方法)
    // ==》数求和问题
    // (4)定义两个指针:左指针(left) 和 右指针(right)
    // (5)找出固定 left, 此时left所指的位置为数组中最小数,再找到两个数和 不大于 target 的最大 right 的位置
    // (6)调整 left 的位置(后移),求解和是否为 target O(n)
    public class Solution {
    public ArrayList<ArrayList> threeSum(int[] num) {
    ArrayList<ArrayList> res = new ArrayList<>();

    if(num == null || num.length < 3){
          return res;
    }
    Arrays.sort(num);// 排序
    for(int i=0;i<num.length-2;i++){
        if(num[i]>0){
            break;// 如果当前数字大于0,则三数之和一定大于0,所以结束循环
        }
        if(i>0 && num[i] == num[i-1]){
            continue;// 去重
        }
        int left = i+1;
        int right = num.length-1;
        while(left<right){
            int sum = num[i]+num[left]+num[right];
            if(sum == 0){
                ArrayList<Integer> list = new ArrayList<>();
                list.add(num[i]);
                list.add(num[left]);
                list.add(num[right]);
                res.add(list);
                
                while(left<right && num[left] == num[left+1]){
                    left++;
                }
                while(left<right && num[right] == num[right-1]){
                    right--;
                }
                left++;
                right--;
            }else if(sum>0){
                right--;
            }else if(sum<0){
                left++;
            }
        }
    }
    return res;
    

    }
    }

// //21.最长递增子序列
// 题目描述
// 给定数组arr,设长度为n,输出arr的最长递增子序列。(如果有多个答案,请输出其中字典序最小的)
// 示例1
// 输入
// [2,1,5,3,6,4,8,9,7]
// 返回值
// // [1,3,4,8,9]
// 下面说说贪心+二分的解法,举例说明基本思路,假设数组arr为[2, 3, 1, 2, 3],vec数组里面存放递增子序列,maxLen数组里存放以元素i结尾的最大递增子序列长度,那么遍历数组arr并执行如下更新规则:

// 初始情况下,vec为[2],maxLen[1]
// 接下来遇到3,由于vec最后一个元素小于3,直接更新,vec为[2,3],maxLen[1,2]
// 接下来遇到1,由于vec最后的元素大于1, 我们在vec中查找大于等于1的第一个元素的下标,并用1替换之,此时vec为[1,3], maxLen[1,2,1]
// 接下来遇到2,由于vec最后的元素大于2,我们在vec中查找大于等于2的第一个元素的下标,并用2替换之,此时vec为[1,2], maxLen[1,2,1,2]
// 接下来遇到3,由于vec最后一个元素小于3,直接更新,vec为[1,2,3],maxLen为[1,2,1,2,3]
// 此时vec的大小就是整个序列中最长递增子序列的长度(但是vec不一定是本题的最终解)
// 对于第二步,假设我们原始数组是arr1,得到的maxLen为[1,2,3,1,3],最终输出结果为res(字典序最小的最长递增子序列),
//res的最后一个元素在arr1中位置无庸置疑是maxLen[i]==3对应的下标,那么到底是arr1[2]还是arr1[4]呢?如果是arr1[2],那么arr1[2]<arr1[4],则maxLen[4]==4,与已知条件相悖。因此我们应该取arr1[4]放在res的最后一个位置。

public class Solution {
/**
* retrun the longest increasing subsequence
* @param arr int整型一维数组 the array
* @return int整型一维数组
*/
public int[] LIS (int[] arr) {
// write code here
int[] maxLen = new int[arr.length];
int[] temp = new int[arr.length];
maxLen[0] = 1;
int tempIndex = 0;
temp[tempIndex]= arr[0];
for(int i=1;i<arr.length;++i){
int left = 0,right = tempIndex;
if(arr[i] > temp[tempIndex]){
++tempIndex;
maxLen[i] = tempIndex+1;
temp[tempIndex] = arr[i];
}else{
while(left<=right){
int mid = (right+left)/2;
if(temp[mid] > arr[i]){
right = mid-1;
}else{
left = mid+1;
}
}
temp[left] = arr[i];
maxLen[i]=left+1;
}
}
int[] res = new int[tempIndex+1];
for(int i= maxLen.length-1;i>=0;–i){
if(maxLen[i] == tempIndex+1){
res[tempIndex] = arr[i];
–tempIndex;
}
}
return res;
}
}

//22.不相邻最大子序列和
// 题目描述
// 给你一个n(1\leq n\leq10^51≤n≤10
// 5
// ),和一个长度为n的数组,在不同时选位置相邻的两个数的基础上,求该序列的最大子序列和(挑选出的子序列可以为空)。
// 3,[1,2,3]
// 返回值:4
// 二:动态规划 创建一个新数组
// 因为不能选择两个相邻的元素,那么对于第i个元素的选择的可能性就包含选择i和不选择i个元素,至于选与不选其实是和第i-1个元素有直接关系的
// 所以需要比较的是 前一项的最大子序和 和加上奔向的子序和 一直比到最后
function subsequence( n , array ) {
// write code here
const dp = new Array(n)
dp[0] = array[0]
dp[1] = Math.max(dp[0],array[1])
for(let i = 2;i<n;i++){
dp[i] = Math.max(dp[i-1],dp[i-2]+array[i]) //更新dp;1.不包含前一个元素,包括本元素;2. 不包括本元素的较大值
}
return dp[n-1]
}
module.exports = {
subsequence : subsequence
};

public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 计算
* @param n int整型 数组的长度
* @param array int整型一维数组 长度为n的数组
* @return long长整型
*/
public long subsequence (int n, int[] array) {
// write code here
long[] dp = new long[n+1];
dp[0] = 0;
dp[1] = array[0];
for(int i=2;i<=n;i++){
dp[i] = Math.max(dp[i-1],dp[i-2]+array[i-1]);
}
return dp[n];
}
}

//23.两个链表的第一个公共结点
// 题目描述
// 输入两个链表,找出它们的第一个公共结点。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)
// 双指针法。创建两个指针p1和p2,分别指向两个链表的头结点,
// 然后依次往后遍历。如果某个指针到达末尾,
// 则将该指针指向另一个链表的头结点;如果两个指针所指的节点相同,
//则循环结束,返回当前指针指向的节点。
//比如两个链表分别为:1->3->4->5->6和2->7->8->9->5->6。短链表的指针p1会先到达尾部,然后重新指向长链表头部,当长链表的指针p2到达尾部时,重新指向短链表头部,此时p1在长链表中已经多走了k步(k为两个链表的长度差值),p1和p2位于同一起跑线,往后遍历找到相同节点即可。其实该方法主要就是用链表循环的方式替代了长链表指针先走k步这一步骤。
// 看下面的链表例子:
// 0-1-2-3-4-5-null
// a-b-4-5-null
// 代码的ifelse语句,对于某个指针p1来说,其实就是让它跑了连接好的的链表,长度就变成一样了。
// 如果有公共结点,那么指针一起走到末尾的部分,也就一定会重叠。看看下面指针的路径吧。
// p1: 0-1-2-3-4-5-null(此时遇到ifelse)-a-b-4-5-null
// p2: a-b-4-5-null(此时遇到ifelse)0-1-2-3-4-5-null
// 因此,两个指针所要遍历的链表就长度一样了!
// 如果两个链表存在公共结点,那么p1就是该结点,如果不存在那么p1将会是null。
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
if(pHead1 == null || pHead2 == null) return null;
//创建2个指针,分别指向两个链表的头结点
ListNode p1 = pHead1;
ListNode p2 = pHead2;
//依次往后遍历
while(p1 != p2){
p1 = p1.next;
p2 = p2.next;
//如果某个指针道道末尾,则将该指针指向另一个链表的头节点;
//如果两个指针所指的节点相同,则循环结束,返回当前指针指向的节点
if(p1 != p2){
if(p1 == null) p1=pHead2;
if(p2 == null) p2 = pHead1;
}
}
return p1;
}
}

function FindFirstCommonNode(pHead1, pHead2)
{
if(pHead1 == null || pHead2 == null) return null;
// write code here
let node1 = pHead1;
let node2 = pHead2;
while(node1 != node2){
node1 = node1.next;
node2 = node2.next;
if(node1 != node2){
if(node1 == null) node1 = pHead2;
if(node2 == null) node2 = pHead1;
}
}
return node1;
}

// //24.设计getMin功能的栈
// 题目描述
// 实现一个特殊功能的栈,在实现栈的基本功能的基础上,再实现返回栈中最小元素的操作
// 输入
// [[1,3],[1,2],[1,1],[3],[2],[3]]
// 返回值
// [1,2]

public class Solution {
/**
* return a array which include all ans for op3
* @param op int整型二维数组 operator
* @return int整型一维数组
*/
public static Stack s = new Stack();//s用来存数据
public static Stack min_s = new Stack();//min_s用来获取最小值
public int[] getMinStack (int[][] op) {
// write code here
ArrayList res = new ArrayList();//结果集
for(int i=0;i<op.length;i++){
if(op[i][0] == 1){//为1就入栈
Push(op[i][1]);
}else if(op[i][0] == 2){//为2就出栈
Pop();
}else{//为3就返回栈中最小元素
res.add(getMin());
}
}
//因为返回类型的缘故我们需要把res中的元素丢在arr数组里面
int[] arr = new int[res.size()];
for(int i=0;i<res.size();i++){
arr[i] = res.get(i);
}
return arr;
}
public void Push(int x){
s.push(x);
if(min_s.empty() || min_s.peek()>=x){
min_s.push(x);//如果min_s为空,或者栈顶元素大于x就进入min_s
}
}
public void Pop(){
if(!s.empty()){
if(s.peek().equals(min_s.peek())){
min_s.pop();//如果min_s栈顶元素和栈s中要出栈的元素相等,那么也需要出栈
}
s.pop();
}
}
public int getMin(){
return min_s.peek();//栈min_s的栈顶元素即为最小值
}
}

//25.大数加法
// 题目描述
// 以字符串的形式读入两个数字,编写一个函数计算它们的和,以字符串形式返回。
// (字符串长度不大于100000,保证字符串仅由’0’~'9’这10种字符组成)
// 输入
// “1”,“99”
// 返回值
// “100”
//我们还可以先把相加的结果放到一个栈中,最后再一个个出栈。其实也是换汤不换药,代码都差不多,
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 计算两个数之和
* @param s string字符串 表示第一个整数
* @param t string字符串 表示第二个整数
* @return string字符串
*/
public String solve (String s, String t) {
// write code here
Stack stack = new Stack<>();
StringBuilder stringBuilder = new StringBuilder();
int i = s.length()-1;
int j = t.length()-1;
int carry = 0;
while(i>=0 || j>=0 || carry != 0){
carry += i>=0?s.charAt(i–)-‘0’:0;
carry += j>=0?t.charAt(j–)-‘0’:0;
stack.push(carry%10);
carry = carry/10;
}
while(!stack.isEmpty()){
stringBuilder.append(stack.pop());
}
return stringBuilder.toString();
}
}

public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 计算两个数之和
* @param s string字符串 表示第一个整数
* @param t string字符串 表示第二个整数
* @return string字符串
*/
public String solve (String s, String t) {
// write code here
StringBuilder stringBuilder = new StringBuilde();
int carry = 0;
int i = s.length()-1;
int j = t.length()-1;
while(i>=0 || j>=0 || carry != 0){
int x = i<0?0:s.charAt(i–)-‘0’;
int y = j<0?0:t.charAt(j–)-‘0’;
int sum = x+y+carry;
stringBuilder.insert(0,sum%10);//插入到s字符串的第一个位置
carry = sum/10;
}
return stringBuilder.toString();
}
}

//26.链表中倒数第K个结点
// 题目描述
// 输入一个链表,输出该链表中倒数第k个结点。
// 如果该链表长度小于k,请返回空。
// 输入
// {1,2,3,4,5},1
// 返回值
// {5}
public ListNode FindKthToTail (ListNode pHead, int k) {
// write code here
//很显然要利用双指针
ListNode fast = pHead;
ListNode slow = pHead;
//fast指针先走k步
for(int i=0;i<k;i++) {
if(fast != null) {
fast = fast.next;
}else {
return null;//还没走完k步就没了说明该链表节点数<k
}
}
//slow fast一起往后走,当fast指向null时,slow就是所求倒数第K个节点
while(fast != null) {
fast = fast.next;
slow = slow.next;
}
return slow;
}
//27.螺旋居住
// 题目描述
// 给定一个m x n大小的矩阵(m行,n列),按螺旋的顺序返回矩阵中的所有元素。
// 示例1
// 输入
// [[1,2,3],[4,5,6],[7,8,9]]
// 返回值
// [1,2,3,6,9,8,7,4,5]
[[1,2,3],
[4,5,6],
[7,8,9]]

import java.util.*;
public class Solution {
public ArrayList spiralOrder(int[][] matrix) {
ArrayList res = new ArrayList<>();
if(matrix.length == 0) return res;
int top =0;
int bottom=matrix.length-1;
int left =0;
int right = matrix[0].length-1;
while(top<(matrix.length+1)/2 && left < (matrix[0].length+1)/2){
//上面 左到右
for(int i = left;i<=right;i++){
res.add(matrix[top][i]);
}
//右边 上到下
for(int i = top+1;i<=bottom;i++){
res.add(matrix[i][right]);
}
//下面 右到左
for(int i=right-1;top != bottom&&i>=left;i–){
res.add(matrix[bottom][i]);
}
//左边 下到上
for(int i=bottom-1;left!=right&&i>=top+1;i–){
res.add(matrix[i][left]);
}
++top;
–bottom;
++left;
–right;
}
return res;
}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值