- 剑指 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 value
public int hammingWeight(int n) {
int mask = 1;
int num = 0;
int max = 1<<31;
while((mask&max)==0) {
if((mask&n)!=0) { // 不要!=1,因为最低位才是1,其余位比较不为1
num++;
}
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;
// 越过前面的0
while(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;
// 设置新结点的random
while(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/)
```c
class 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') // 十位不能为0
return 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要同时增加1
if(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/)
![image.png](https://cdn.nlark.com/yuque/0/2021/png/8429887/1618239440084-5639d9eb-8255-4878-b242-0079e28ca20f.png#align=left&display=inline&height=421&margin=%5Bobject%20Object%5D&name=image.png&originHeight=421&originWidth=576&size=21323&status=done&style=none&width=576)
- 两个指针l=1,r=2;
- 计算这个区间中数的大小
- 如果数小于,则r++
- 大于,则l++
- 等于,则r++
```java
class 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;
}
}