lt912 最佳见面地点 meeting point
现在有三人分别居住在(0,0), (0,4), 和 (2,2)1
2
3
4
51 - 0 - 0 - 0 - 1
| | | | |
0 - 0 - 0 - 0 - 0
| | | | |
0 - 0 - 1 - 0 - 0
点(0, 2)是最佳见面地点,最小的路程总和为2+2+2=6,返回6。
思路:只要见面地点在A,B中间,到A,B的花费都是 AB长度。
把横/纵坐标排序,每次取最大最小的两个,差就是AB。
1 | public int minTotalDistance(int[][] grid) { |
462 选一个数字 +1 / -1 元素相等的最小步数
Input:
[1,2,3]
Output:
2
1 | public int minMoves2(int[] nums) { |
719 数组中两两匹配,第k小的两数之差
nums = [1,3,1]
k = 1
输出:0
解释:
所有数对如下:
(1,3) -> 2
(1,1) -> 0
(3,1) -> 2
因此第 1 个最小距离的数对是 (1,1),它们之间的距离为 0。
532 数组中有几个相差k的pair
输入: [3, 1, 4, 1, 5], k = 2
输出: 2
解释: 数组中有两个 2-diff 数对, (1, 3) 和 (3, 5)。
尽管数组中有两个1,但我们只应返回不同的数对的数量。
set的解法33% //todo比双指针慢
220 数组中是否有相差<=t,idx差<=k 的元素
Input: nums = [1,2,3,1], k = 3, t = 0
Output: true
2.桶
1.40% 用容量k的TreeSet,超过k删除最左
判断能否和ceiling合floor<=t
如果不能 放入treeset等待
219 是否有重复元素 下标相差<=k
Input: nums = [1,2,3,1], k = 3
Output: true
放进一个FIFO大小为(k+1) 相差k 的set,当有add失败的时候就true
数对
x和y均不大于n, 并且x除以y的余数大于等于k,一共有多少对(x,y)
输入:5 2
输出:7
满足条件的数对有(2,3),(2,4),(2,5),(3,4),(3,5),(4,5),(5,3)
思路:
如果 y > x 能产生的余数是1-(y-1), 所以y>k,并且产生的余数>=k的有(y-k)个
对于一个y,n个数字产生的完整余数区间有n/y个
y = 3 -> +2 (2,3)(5,3) 1-5的余数 1 2 0| 1 2
y = 4 -> +2 (2,4)(3,4) 1-5的余数 1 2 3 0 | 1
y = 5 -> +3 (2,5)(3,5)(4,5) 1-5的余数 1 2 3 4 | 0
对于最后一个区间不满y个数,最后一个区间>=k的个数是n%y+1-k ,例如5%3->2最后一个循环有2个符合的
特殊情况如果k=0 xy可以相等n*n个1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
long n = sc.nextLong();
int k = sc.nextInt();
if(k == 0)System.out.println(n*n);
else {
long cnt = 0;
for (int y = k + 1; y <= n; y++) {
cnt += (n / y) * (y - k);
if (n % y >= k) {
cnt += (n % y) + 1 - k;
}
}
System.out.println(cnt);
}
}
376. Wiggle Subsequence 最长摇摆序列
Input: [1,17,5,10,13,15,10,5,16,8]
Output: 7
One is [1,17,10,13,10,16,8].
第一个差能正能负,差正负交替的最长子序列。
贪心:1
2
3
4
5
6
7
8
9
10public int wiggleMaxLength(int[] nums) {
if (nums == null) return 0;
if (nums.length <= 1) return nums.length;
int f = 1, b = 1;
for (int i = 1; i < nums.length; i++) {
if (nums[i] > nums[i-1]) f = b + 1;
else if (nums[i] < nums[i-1]) b = f + 1;
}
return Math.max(f, b);
}
正确做法:动态规划只要记住-1位置上的最大值就好了1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public int wiggleMaxLength(int[] nums) {
if(nums == null)return 0;
int n = nums.length;
if(n < 2)return n;
int predif = 0;
int cnt = 1;
for(int i =1;i<n;i++){
int dif = nums[i] - nums[i-1];
if(dif >0 && predif <=0 ||
dif <0 && predif >=0){
cnt++;
predif = dif;
}
}
return cnt;
}
209最小连续子数组 和>=K 的长度
Input: s = 7, nums = [2,3,1,2,4,3]
Output: 2
Explanation: the subarray [4,3]
1 | public int minSubArrayLen(int s, int[] nums) { |
1 二分搜索
暴力法搜索前缀数组sum[j]-sum[i]+nums[i]>=k
的最短ij
二分发寻找sum[j] >= sum[i]-nums[i]+k
j的最小值
560 数组中有多少个和为k的子数组
输入:nums = [1,1,1], k = 2
输出: 2 , [1,1] 与 [1,1] 为两种不同的情况。
同930 一模一样,查找可以组成k的前缀,计数前缀
69%
1 | public int subarraySum(int[] nums, int k) { |
930 01数组中有多少个和=target的子数组
输入:A = [0,0,0,0,0], S = 0
输出:15 5+4+3+2+1
思路: 计算前缀和[1,1,2,2,3]
并放入map计数,{1:2,2:2,3:1}
步骤[0,0,0,0,0] 初始化map{0:1}
,扫描到第一个0,查找map中S-0=0有几个,cnt=1,更新map{0:2}
,扫描到第二个0,cnt=1+2…最后一个0,cnt+1+2+3+4+5 = 151
2
3
4
5
6
7
8
9
10
11
12
13public int numSubarraysWithSum(int[] A, int S) {
Map<Integer, Integer> c = new HashMap<>();
c.put(0, 1);
int psum = 0, res = 0;
for (int i : A) {
psum += i;
// 查找前缀
res += c.getOrDefault(psum - S, 0);
// 当前前缀计数
c.put(psum, c.getOrDefault(psum, 0)+1);
}
return res;
}
713 乘积<k
的子数组的个数
Input: nums = [10, 5, 2, 6], k = 100
Output: 8
Explanation: The 8 subarrays that have product less than 100 are: [10], [5], [2], [6], [10, 5], [5, 2], [2, 6], [5, 2, 6]
.
Note that [10, 5, 2]
is not included as the product of 100 is not strictly less than k.
输入[1,2,3,4] k = 10
当s = 0,e = 0 窗口只有[1]
窗口乘积p = 1 ,子数组个数 1 :[1]
s = 0,e = 1 窗口[1,2]
p = 2 子数组个数3: [[1], [2],[1,2]]
(+2)
s = 0,e = 2 窗口[1,2,3]
p = 6 子数组个数3: [[1],[2][1,2], [3],[2,3],[1,2,3]]
(+3)
每次子数组的增长个数就是窗口大小
如果 p >k 则s向右
s = 1,e = 3 窗口[2,3,4]
p = 24
s = 2,e = 3窗口[3,4]
p = 12 子数组个数[[3], [4][3,4]]]
(+2)
1 | public int numSubarrayProductLessThanK(int[] nums, int k) { |
1 | public int numSubarrayProductLessThanK(int[] nums, int k) { |
862 和至少为K的最短子数组
Input: A = [2,-1,2], K = 3
Output: 3
思路:用前缀和找区间和,关键:递增有序栈,
用当前值更新队尾,如果当前的presum比队尾presum小,则下一个减这个得到的区间更短而且值更大。
1 | public int shortestSubarrayWindow(int[] A, int K) { |
283 Move Zeroes 所有0移到后面
把0都放到后面并且保证原来顺序不变。 没有额外空间。
Input: [0,1,0,3,12]
Output: [1,3,12,0,0]
思路:两个指针,如果找到非零,则和前面那个指针的交换
j保证左边没有0,扫一遍i保证所有的非0都移到j的左边。
011->101->110
1 | public void moveZeroes(int[] nums) { |
优化点:如果数组全部都是非零元素,每个元素都自己和自己交换了,防止自己和自己交换这种操作:1
2
3
4
5
6
7
8
9public void moveZeroes(int[] nums) {
for(int i = 0,j =0; i < nums.length; i++) {
if(nums[i] != 0) {
if(i!=j)
swap(nums,i,j++);
else j++;
}
}
}
88 Merge Sorted Array
Input:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3
Output: [1,2,2,3,5,6]
1 | public void merge(int A[], int m, int B[], int n) { |
1 | public void merge(int[] nums1, int m, int[] nums2, int n) { |
75 !!!Sort Colors
Input: [2,0,2,1,1,0]
Output: [0,0,1,1,2,2]
不会!
思路:
left 左边都是0 是1
right 右边都是2 right是0/1
用idx遍历,
1)如果从left开始是1,可以后移,保证00011是正确的顺序
2)如果是2,和right换,right–,因为idx是后面的数字还没遍历,所以idx不动
3)如果是0,和left换,但是left是肯定对的,所以idx++,left被换成0了,保证了左边是0,left++。
4)注意终止条件,因为right可能是0,所以当i==right的时候还可能跟right换一下,直到i>right1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public void sortColors(int[] nums) {
int n = nums.length;
int left = 0;
int right = n-1;
int i = 0;
while(i <= right){
if(nums[i] == 0){
swap(nums,i++,left++);
}
else if(nums[i] == 2){
swap(nums,i,right--);
}else
i++;
}
}
228 Summary Ranges
输入: [0,1,2,4,5,7]
输出: [“0->2”,”4->5”,”7”]
217 Contains Duplicate
判断数组中是否有重复元素
Input: [1,2,3,1]
Output: true
1)两个for循环
2)排序
3)set
275 H-Index II
排好序的h-index
Input: citations = [0,1,3,5,6]
Output: 3
274 H-Index
所有学术文章N中有h篇论文分别被引用了至少h次,他的H指数就是h.其他N-h篇论文都没有h次引用
Input: citations = [3,0,6,1,5]
Output: 3
解释: 给定数组表示研究者总共有 5 篇论文,每篇论文相应的被引用了 3, 0, 6, 1, 5 次。
由于研究者有 3 篇论文每篇至少被引用了 3 次,其余两篇论文每篇被引用不多于 3 次,所以她的 h 指数是 3。
AC 方法不对
正确做法:桶计数1
2
3
4
5
6
7
8
9
10
11
12
13
14public int hIndex(int[] citations) {
int n = citations.length;
int[] cnt = new int[n+1];
for(int ci : citations){
if(ci > n)cnt[n]++;
else cnt[ci]++;
}
int rst = 0;
for(int i = n;i>=0;i--){
rst+=cnt[i];
if(rst >= i)return i;
}
return 0;
}
485 Max Consecutive Ones 最多连续的1
Input: [1,1,0,1,1,1]
Output: 3
AC1
2
3
4
5
6
7
8
9
10
11
12
13
14public int findMaxConsecutiveOnes(int[] nums) {
int cnt = 0;
int max = 0;
for(int i =0;i<nums.length;i++){
if(nums[i] != 1 && cnt>0){
max = Math.max(max,cnt);
cnt =0;
}else if(nums[i] ==1){
cnt++;
}
}
max = Math.max(max,cnt);
return max;
}
229 Majority Element II
找到所有出现次数超过 ⌊ n/3 ⌋ 次的数字
Input: [3,2,3]
Output: [3]
不会
思路:1)超过n/3的数最多只能有2个 注意顺序
1 | public List<Integer> majorityElement(int[] nums) { |
!!!169 众数 Boyer-Moore Voting Algorithm
Input: [3,2,3]
Output: 3
关键:计数变量1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public int majorityElement(int[] nums) {
int rst = 0;
int cnt =0;
for(int num:nums){
if(cnt == 0){
rst = num;
}
if(rst != num){
cnt--;
}else{
cnt++;
}
}
return rst;
}
1.hashmap,直到有计数>n/2 break->return 11%
2.随机数44% 因为一半以上都是这个数,可能只要循环两边就找到了1
2
3
4
5
6
7
8
9
10
11public int majorityElement(int[] nums){
Random random = new Random(System.currentTimeMillis());
while(true){
int idx = random.nextInt(nums.length);
int choose = nums[idx];
int cnt = 0;
for(int num:nums){
if(num==cur&&++cnt>nums.length/2)return num;
}
}
}
3.39% 计算用每个数字的每一位投票,1的个数>n/2则为11
2
3
4
5
6
7
8
9
10
11
12
13
14public int majorityElement(int[] nums){
int n = nums.length;
int rst =0;
int mask =0;
for(int i=0;i<32;i++){
mask = 1<<i;
int cnt =0;
for(int num:nums){
if((num&mask)!=0)cnt++;
}
if(cnt>n/2)rst|=mask;
}
return rst;
}
4.moore voting 在线算法92%
1 | public int majorityElement(int[] nums){ |
优化100%
每次取两个不同的数删除,最后剩下的返回
1 | class Solution { |
5.排序取中间的数
6.C++专有 部分排序1
2
3
4int majorityElement(vector<int> & nums){
nth_element(nums.begin(),nums.begin()+nums.size()/2,nums.end());
return nums[nums.size()/2];
}
7.分治???
119 !Pascal’s Triangle II 帕斯卡三角形的第k行
Input: 3
Output: [1,3,3,1]
不会
118 Pascal’s Triangle
Input: 5
Output:1
2
3
4
5
6
7[
[1],
[1,1],
[1,2,1],
[1,3,3,1],
[1,4,6,4,1]
]
1 | public List<List<Integer>> generate(int numRows) { |
134 !Gas Station 环形加油站出发点
找到一个起点可以获得gas[i]汽油,到下一个花费cost[i]可以遍历完所有加油站回到起点的点。
Input:
gas = [1,2,3,4,5]
cost = [3,4,5,1,2]
Output: 3
AC但是方法不对
前段总的余量为负,即油不够用,要想有解,那么后段油量应该为正,此时才可能有解.
反之,如果前段就为正了,那么显然可以直接选择前面的点为起点;
如果整段加起来都是负的,那么无解
1 | public int canCompleteCircuit(int[] gas, int[] cost) { |
299 !Bulls and Cows 猜对了几个字符
A表示位置对+数值对,B表示位置不对。
Input: secret = “1123”, guess = “0111”
Output: “1A1B”
关键:计数,如果secret当前字符的计数<0,表示在guess出现过,b++,然后再计数这个字符。
注意对secret和guess的当前字符都判断是否之前出现过,分别计数b。
1 | public String getHint(String secret, String guess) { |
41 !First Missing Positive 数组中第一个不存在的正数
Input: [1,2,0]
Output: 3
不会 思路:用[0-n-1]存储数组中出现的[1-n]如果超出长度不计,再遍历一遍第一个没标记的1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23public int firstMissingPositive(int[] nums) {
int n = nums.length;
if(n<1)return 1;
int i = 0;
while(i<n){
if(nums[i]>0 && nums[i]-1<n && i!=nums[i]-1 && nums[nums[i]-1]!=nums[i] ){
swap(nums,i,nums[i]-1);
}
else i++;
}
i = 0;
while(i<n){
if(i+1!=nums[i])break;
i++;
}
return i+1;
}
private void swap(int[] arr,int i,int j){
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
189 Rotate Array 旋转数组
Input: [1,2,3,4,5,6,7] and k = 3
Output: [5,6,7,1,2,3,4]
注意划分[0,k-1],[k,n-1]1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public void rotate(int[] nums, int k) {
int n = nums.length;
if(n<2 || k == 0)return;
k %= n;
reverse(nums,0,n-1);
reverse(nums,0,k-1);
reverse(nums,k,n-1);
}
private void reverse(int[] nums,int i,int j){
while(i<j){
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
i++;j--;
}
}
277 Find the Celebrity (lintcode)
Celebrity Problem 所有人都认识他但是他不认识所有人
方法1:找全是0的行,O(n^2)
方法2: 如果A认识B,则A肯定不是名人 O(N);A不认识B,则A可能是名人,B肯定不是名人
A,B不认识,重新入栈A
A,C认识,入栈C
方法3:双指针1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19int findCele(int[][]Matrix){
int n = Matrix.length;
int a = 0;
int b = n-1;
while (a<b){
if(Matrix[a][b]==1){
a++;
}
else{
b--;
}
}
for (int i = 0; i <n ; i++) {
//不是自己,但是别人不认识他,或者他认识别人
if(i!=a&&Matrix[i][a]!=1||Matrix[a][i]==1)
return -1;
}
return a;
}
80 !Remove Duplicates from Sorted Array II有序数组只保留每个2个不同元素
Given nums = [1,1,1,2,2,3],
length = 5
调了好久1
2
3
4
5
6
7public int removeDuplicates(int[] nums) {
int i = 0;
for (int n : nums)
if (i < 2 || n > nums[i-2])
nums[i++] = n;
return i;
}
26 !Remove Duplicates from Sorted Array 有序数组只保留不同元素
Given nums = [1,1,2],
2
长度bug调了好久1
2
3
4
5
6
7
8
9
10
11public int removeDuplicates(int[] nums) {
int n = nums.length;
if(n<2)return n;
int cnt = 1;
for(int i =1;i<n;i++){
if(nums[i]-nums[i-1]>0){
nums[cnt++] = nums[i];
}
}
return cnt;
}
27 Remove Element
熟练1
2
3
4
5
6
7
8
9public int removeElement(int[] nums, int val) {
int cnt = 0;
for(int i =0;i<nums.length;i++){
if(nums[i]!=val){
nums[cnt++] = nums[i];
}
}
return cnt;
}
121 Best Time to Buy and Sell Stock 只能买卖一次 买卖股票的利润
输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
能一次AC 熟练1
2
3
4
5
6
7
8
9
10
11 public int maxProfit(int[] prices) {
if(prices.length <1)return 0;
// 之前最低
int pre = prices[0];
int rst = 0;
for(int i = 1;i < prices.length;i++){
rst = Math.max(rst,prices[i]-pre);
pre = Math.min(pre,prices[i]);
}
return rst;
}