- 剑指 Offer 14- I. 剪绳子">剑指 Offer 14- I. 剪绳子
 - 剑指 Offer 15. 二进制中1的个数">剑指 Offer 15. 二进制中1的个数
 - 剑指 Offer 16. 数值的整数次方">剑指 Offer 16. 数值的整数次方
 - 剑指 Offer 17. 打印从1到最大的n位数">剑指 Offer 17. 打印从1到最大的n位数
 - 剑指 Offer 36. 二叉搜索树与双向链表">剑指 Offer 36. 二叉搜索树与双向链表
 - 229. 求众数 II">229. 求众数 II
 - 剑指 Offer 35. 复杂链表的复制">剑指 Offer 35. 复杂链表的复制
 - 剑指 Offer 40. 最小的k个数">剑指 Offer 40. 最小的k个数
 - ">

 - 剑指 Offer 33. 二叉搜索树的后序遍历序列">剑指 Offer 33. 二叉搜索树的后序遍历序列
 - 剑指 Offer 46. 把数字翻译成字符串">剑指 Offer 46. 把数字翻译成字符串
 - 剑指 Offer 45. 把数组排成最小的数">剑指 Offer 45. 把数组排成最小的数
 - 剑指 Offer 44. 数字序列中某一位的数字">剑指 Offer 44. 数字序列中某一位的数字
 - 剑指 Offer 49. 丑数">剑指 Offer 49. 丑数
 - 剑指 Offer 41. 数据流中的中位数">剑指 Offer 41. 数据流中的中位数
 - 剑指 Offer 56 - II. 数组中数字出现的次数 II">剑指 Offer 56 - II. 数组中数字出现的次数 II
 - 剑指 Offer 56 - I. 数组中数字出现的次数">剑指 Offer 56 - I. 数组中数字出现的次数
 - 剑指 Offer 51. 数组中的逆序对">剑指 Offer 51. 数组中的逆序对
 - 剑指 Offer 59 - I. 滑动窗口的最大值">剑指 Offer 59 - I. 滑动窗口的最大值
 
剑指 Offer 14- I. 剪绳子

- 使用一个数组dp来代表长度为i时候,乘积的最大值
 - 对于当前i,遍历最后一个长度,加入最后一段长度是j   
- 那么对于i-j来说,有两个取值
- 取(i-j)剪开情况的最大值j * dp[i - j]
 - (i-j)长度不剪开j * (i - j)
 
 
 - 那么对于i-j来说,有两个取值
 dp[i] = max(dp[i], max(j (i - j), j dp[i - j]))
class Solution {public int cuttingRope(int n) {int[] dp = new int[n+1];// for(int i = 0;i<=n;i++) {// dp[i][1] = i;// }dp[1]=1;dp[2]=1;for(int i = 3; i <= n;i++) {for(int j = 1; j < i ; j++) {dp[i] = Math.max(dp[i-j]*j,dp[i]);dp[i] = Math.max((i-j)*j,dp[i]);}}// System.out.println(Arrays.toString(dp));return dp[n];}}
剑指 Offer 15. 二进制中1的个数

public class Solution {// you need to treat n as an unsigned valuepublic int hammingWeight(int n) {int mask = 1;int num = 0;int max = 1<<31;while((mask&max)==0) {if((mask&n)!=0) { // 不要!=1,因为最低位才是1,其余位比较不为1num++;}mask<<=1;}// (mask&max)!=0的情况,即maks=1<<31的时候if((mask&n)!=0) {num++;}return num;}}
剑指 Offer 16. 数值的整数次方

注意负数
注意min没有整数对应
class Solution {public double myPow(double x, int n) {// 注意-2147483648的情况,没有对应的正数值if(n<0) {int t = n/2;if(n%2==0) {double res = myPow(x,-t);return 1.0/(res*res);} else {double res = myPow(x,-t);return 1.0/(res*res*x);}}if(n==1)return x;if(n==0)return 1;if(n%2==0) {double res = myPow(x,n/2);return res*res;} else {double res = myPow(x,n/2);return res*res*x;}}}
剑指 Offer 17. 打印从1到最大的n位数

class Solution {public int[] printNumbers(int n) {StringBuilder builder = new StringBuilder();List<Integer> list= new ArrayList();dfs(n,0,builder,list);int[] res = new int[list.size()];for(int i = 0 ; i < res.length;i++)res[i] = list.get(i);return res;}void dfs(int n,int index,StringBuilder builder,List<Integer> list) {if(n==index) {String s = builder.toString();int i = 0;// 越过前面的0while(i<s.length() && s.charAt(i)=='0') i++;if(i!=builder.length()) // 不为0则添加list.add(Integer.parseInt(s.substring(i)));return;}for(int i = 0 ; i <= 9 ; i++) {builder.append(i);dfs(n,index+1,builder,list);builder.deleteCharAt(builder.length()-1);}}}
剑指 Offer 36. 二叉搜索树与双向链表

递归左子树
- 返回左子树最右边的节点t
 - 让root的left指向t,t的右子树指向root
 
- 递归右子树
- 返回右子树的最左边的节点t
 - 让root的right指向t,t的左子树指向root
 
 
class Solution {public Node treeToDoublyList(Node root) {if(root==null)return null;// 处理根节点if(root.left!=null) {Node l = tree(root.left,true);root.left = l;l.right = root;}// 跟的右子树if(root.right!=null) {Node r = tree(root.right,false);r.left = root;root.right = r;}Node tail = root;while(tail.right!=null)tail = tail.right;Node head = root;while(head.left!=null)head = head.left;head.left = tail;tail.right = head;return head;}public Node tree(Node root,boolean left) {Node l = null;Node r = null;if(root.left!=null) {l = tree(root.left,true);}if(root.right!=null) {r = tree(root.right,false);}if(l!=null) {l.right = root;root.left = l;}if(r!=null){r.left = root;root.right = r;}Node now = root;if(left) {while(now.right!=null)now = now.right;return now;} else {while(now.left!=null)now = now.left;return now;}}}
229. 求众数 II
难度中等353
moore投票法,O(N)时间,O(1)空间。本质上是利用两个变量cm, cn记录频率最高的两个元素m, n的频率,遇到m,n自增对应的频率,遇到非m,非n,自减cm,cn。最后再重置cm,cn为0,再遍历一遍数组查看获取的最高频率的m,n的频率是否大于1/3的总元素个数。因为有可能最高频率的元素并不大于1/3的总元素个数(比如[1,1,2,2,3,4,5,6,7,8,9])
class Solution {public List<Integer> majorityElement(int[] nums) {int a1 = nums[0];int b1 = 0;int a2 = nums[0];int b2 = 0;for(int num:nums) {if(a1==num) {b1++;continue;}if(a2==num) {b2++;continue;}if(b1==0){a1 = num;b1=1;continue;}if(b2==0) {a2 = num;b2=1;continue;}b1--;b2--;}b1=0;b2=0;for(int n:nums){if(n==a1) {b1++;} else if(n==a2){b2++;}}List<Integer> list = new ArrayList();if(b1*3>nums.length)list.add(a1);if(b2*3>nums.length)list.add(a2);return list;}}
剑指 Offer 35. 复杂链表的复制


class Solution {public Node copyRandomList(Node head) {Node now = head;// 复制新节点,将其放入原节点的后面while(now != null) {Node copyNode = new Node(now.val);copyNode.next = now.next;now.next = copyNode;now = now.next.next;}now = head;// 设置新结点的randomwhile(now!=null) {if(now.random!=null) {now.next.random = now.random.next;}now = now.next.next;}// now = head;// while(now!=null){// System.out.print(now.val+" ");// now = now.next;// }Node dummy = new Node(-1);Node pre = dummy;now = head;// 拆分节点while(now!=null) {pre.next = now.next;now.next = now.next.next;pre = pre.next;pre.next=null;now = now.next;}return dummy.next;}}
剑指 Offer 40. 最小的k个数
快排
class Solution {public int[] getLeastNumbers(int[] arr, int k) {find(arr,0,arr.length-1,k-1);int[] res = new int[k];for(int i = 0 ; i < k ; i++)res[i] = arr[i];return res;}void find(int[] arr,int l,int r,int k) {if(l>=r)return;int pivot = arr[l];int left = l;int right = r;while(left<right) {while(left<right && arr[right]>=pivot)right--;while(left<right && arr[left]<=pivot)left++;if(left<right) {int t = arr[left];arr[left] = arr[right];arr[right] = t;}}arr[l] = arr[left];arr[left] = pivot;if(left<k) {find(arr,left+1,r,k);} else if(left>k) {find(arr,l,left-1,k);}}}
剑指 Offer 33. 二叉搜索树的后序遍历序列

```java
class Solution {
  public boolean verifyPostorder(int[] postorder) {return find(postorder,0,postorder.length-1);
}
boolean find(int[] postorder,int l,int r) {if(l>=r)return true;int p = l;while(postorder[p]<postorder[r]) p++; // 左子树int m = p; // m记录的是第一个右子树的节点while(postorder[p]>postorder[r]) p++; // 右子树// p==r的意义是:/*5/3\6这样6,3,5:6和3符合规则,3和5符合规则,但是5,6不符合规则;是为了防止非直接父节点的冲突*/return p==r && find(postorder,l,m-1) && find(postorder,m,r-1);}
}
<a name="eihXN"></a>#### [剑指 Offer 42. 连续子数组的最大和](https://leetcode-cn.com/problems/lian-xu-zi-shu-zu-de-zui-da-he-lcof/)```cclass Solution {public int maxSubArray(int[] nums) {int max = nums[0];int res = nums[0];for(int i = 1 ; i < nums.length;i++) {if(res<0) { // 放弃之前的子序和res = 0;}res+= nums[i];max = Math.max(res,max);}return max;}}
剑指 Offer 46. 把数字翻译成字符串

class Solution {public int translateNum(int num) {int a = 1; // -1 index 初试化int b = 1; // 0 index 初始化char[] ch = (num+"").toCharArray();for(int i = 1;i<ch.length;i++) {int t = 0;if(check(ch[i-1],ch[i])) {t+=a;}t+=b;a = b;b = t;}return b;}boolean check(char a,char b) {if(a=='0') // 十位不能为0return false;int res = 0;res += (a-'0');res = res * 10 + (b-'0');if(res>0 && res <= 25) {return true;}return false;}}
剑指 Offer 45. 把数组排成最小的数


class Solution {public String minNumber(int[] nums) {PriorityQueue<String> queue = new PriorityQueue<String>(new Comparator<String>(){public int compare(String s1,String s2) {return (s1+s2).compareTo(s2+s1);}});for(int num:nums) {queue.add(num+"");}StringBuilder builder = new StringBuilder();while(queue.size()!=0) {builder.append(queue.poll());}return builder.toString();}}==== 标准答案class Solution {public String minNumber(int[] nums) {String[] strs = new String[nums.length];for(int i = 0 ;i < strs.length;i++) {strs[i] = String.valueOf(nums[i]);}Arrays.sort(strs,(x,y)->(x+y).compareTo(y+x));StringBuilder builder = new StringBuilder();for(int i = 0 ;i < strs.length;i++) {builder.append(strs[i]);}return builder.toString();}}
剑指 Offer 44. 数字序列中某一位的数字

class Solution {public int findNthDigit(int n) {int digit = 1;long start = 1;long count = 9;while (n > count) { // 1.n -= count;digit += 1;start *= 10;count = digit * start * 9;}long num = start + (n - 1) / digit; // 2.return Long.toString(num).charAt((n - 1) % digit) - '0'; // 3.}}作者:jyd链接:https://leetcode-cn.com/problems/shu-zi-xu-lie-zhong-mou-yi-wei-de-shu-zi-lcof/solution/mian-shi-ti-44-shu-zi-xu-lie-zhong-mou-yi-wei-de-6/来源:力扣(LeetCode)著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
剑指 Offer 49. 丑数


class Solution {public int nthUglyNumber(int n) {int a2 = 0;int a3 = 0;int a5 = 0;int[] arr = new int[n];arr[0] = 1;for(int i = 1; i < n ; i++) {int n2 = 2*arr[a2];int n3 = 3*arr[a3];int n5 = 5*arr[a5];int m = Math.min(n2,Math.min(n3,n5));arr[i] =m;if(m==n2) a2++;//对于6来说,2*3=6;3*2=6;所以a2和a3要同时增加1if(m==n3) a3++;if(m==n5) a5++;}return arr[n-1];}}
剑指 Offer 41. 数据流中的中位数

class MedianFinder {PriorityQueue<Integer> q1 = null;PriorityQueue<Integer> q2 = null;/** initialize your data structure here. */public MedianFinder() {q1 = new PriorityQueue(new Comparator<Integer>(){public int compare(Integer i1,Integer i2) {return i2-i1;}});q2 = new PriorityQueue(new Comparator<Integer>(){public int compare(Integer i1,Integer i2) {return i1-i2;}});}public void addNum(int num) {int s1 = q1.size();int s2 = q2.size();if(s1==0) { // 初始化的状态q1.add(num);} else if(s1==s2) { // 两者大小相同的时候,需要挑一个元素放到前半个中if(num < q2.peek()) { // 当前元素比较小,可以直接放入前一半q1.add(num);} else { // 当前元素大于后半段的第一个,需要将后半段的第一个加入前半段q1.add(q2.poll());q2.add(num);}} else {if(q1.peek()>num) {q2.add(q1.poll());q1.add(num);} else {q2.add(num);}}}public double findMedian() {int s1 = q1.size();int s2 = q2.size();if(s1==s2) {return (q1.peek()+q2.peek())/2.0;}return q1.peek()/1.0;}}
剑指 Offer 56 - II. 数组中数字出现的次数 II

- 对数组的每个数
- 记录当前数的每一位的数量,如果第i位为1,那么count[i]+=1;
 
 - 现在已经得到所有数的第i位的个数
 - count[i]%=3;
 根据count计算结果
class Solution {public int singleNumber(int[] nums) {int[] count = new int[32];for(int i = 0 ; i < nums.length; i++) {int now = nums[i];for(int j = 0 ; j < 32 ; j++) {if(now==0)break;count[j] += 1&now; // 记录当前数的第j位now = now>>>1;}}for(int i = 0 ; i< 32;i++) {count[i] %= 3;}int res = 0;for(int i = 0 ; i < 32;i++) {res += (count[i]<<i);}return res;}}
剑指 Offer 56 - I. 数组中数字出现的次数

全部异或一边,得到两个只出现一次的x,y的值得z=x^y,找出z二进制表示里面为1的一位,这边是对于这个位来说,可以把x,y分成不一样的组,所以就可以求出来了.class Solution {public int[] singleNumbers(int[] nums) {int flag = 0;for(int i = 0 ; i < nums.length; i++) {flag^=nums[i];}int j = 0;while(true) {if((flag&1)==1) {break;}j++;flag>>>=1;}int f1 = 0;int f2 = 0;for(int i = 0 ; i < nums.length; i++) {if(((nums[i]>>j)&1)==1) {f1 ^= nums[i];} else {f2 ^= nums[i];}}return new int[]{f1,f2};}}
剑指 Offer 51. 数组中的逆序对


```java
class Solution {int result = 0; public int reversePairs(int[] nums) {
divid(nums,0,nums.length-1);return result;
}
void divid(int[] nums,int l,int r) {if(l>=r)return;int m = l+r>>1;divid(nums,l,m);divid(nums,m+1,r);if(nums[m]<=nums[m+1])return;merge(nums,l,m,r);}void merge(int[] nums,int l,int m,int r) {int[] arr = new int[r-l+1];int index = 0;int len = arr.length;int l1 = l;int l2 = m+1;int res = 0;while(index<len) {if(l1==m+1) {arr[index] = nums[l2++];} else if(l2==r+1) {arr[index] = nums[l1++];res += (l2-m-1);} else {if(nums[l1]<=nums[l2]) {arr[index] = nums[l1++]; // 如果两个开始位置相等,则前面的一个先移动res += (l2-m-1);} else {arr[index] = nums[l2++];}}index++;}for(int i = l;i<=r;i++) {nums[i] = arr[i-l];}result+=res;// System.out.println(result);// System.out.println(Arrays.toString(nums));}
}
<a name="A46gI"></a>#### [剑指 Offer 57 - II. 和为s的连续正数序列](https://leetcode-cn.com/problems/he-wei-sde-lian-xu-zheng-shu-xu-lie-lcof/)- 两个指针l=1,r=2;- 计算这个区间中数的大小- 如果数小于,则r++- 大于,则l++- 等于,则r++```javaclass Solution {public int[][] findContinuousSequence(int target) {List<int[]> list = new ArrayList();for(int l = 1,r = 2;l<r;) {int sum = (l+r)*(r-l+1);if(target*2==sum) {int[] nums = new int[r-l+1];for(int i = l;i<=r;i++) {nums[i-l] = i;}list.add(nums);r++;} else if (target*2<sum) {l++;} else {r++;}}int[][] arr = new int[list.size()][];for(int i = 0 ; i < arr.length;i++) {arr[i] = list.get(i);}return arr;}}
剑指 Offer 59 - I. 滑动窗口的最大值

- 单调队列
- 判断队头是不是失效了
 - 将小于等于当前元素的数据全部出列
class Solution {public int[] maxSlidingWindow(int[] nums, int k) {if(nums.length==0)return new int[]{};LinkedList<Integer> queue = new LinkedList();for(int i = 0; i < k ; i++) { // 初始化链表while(!queue.isEmpty() && nums[queue.getLast()] < nums[i]) {queue.removeLast();}queue.add(i);}int[] res = new int[nums.length-k+1];int index = 0;res[index++] = nums[queue.peek()];// 遍历剩下的元素for(int i = k ; i < nums.length; i++) {if(queue.peek() == i-k) {queue.poll();}while(!queue.isEmpty() && nums[queue.getLast()] <= nums[i]) {queue.removeLast();}queue.add(i);res[index++] = nums[queue.peek()];}return res;}}
 
 
