思路一:先将数组排序,再选前k个数输出即可。时间复杂度O(N*logN)
思路二:题目只是要求将前k小的数字输出,并没有要求输出的顺序,因此我们可以基于快速排序将数组划分,只要将数组划分为最小的k个数字和其他数字即可。我们采用第二种方法。时间复杂度O(N)。
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
if( k >= arr.length) return arr;
return quicksort(arr,0,arr.length-1,k);
}
public int[] quicksort(int[] arr,int l,int r,int k){
int mid = arr[(l+r)/2];
int i = l-1,j = r+1;
while(i < j){
do i++;while(arr[i]<mid);
do j--;while(arr[j]>mid);
if(i < j){
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
if(i > k) return quicksort(arr,l,j,k);
if(i < k) return quicksort(arr,j+1,r,k);
return Arrays.copyOf(arr,k);
}
}
本题是典型的动态规划题目,通过遍历一遍数组就可以找到连续子数组的最大和。nums[i] += Math.max(0,nums[i-1])
就是将数组的每一位更新为当前遍历到的子数组的最大和,然后res记录总体最大和,遍历结束就得出结果。
class Solution {
public int maxSubArray(int[] nums) {
int res = nums[0];
for(int i = 1; i < nums.length; ++i){
nums[i] += Math.max(0,nums[i-1]);
res = Math.max(res,nums[i]);
}
return res;
}
}
本题的重点是要加入一个辅助栈stack来模拟完成栈的压入操作,每当压入一个元素都要与出栈数组poped的出栈元素比较,如果相等则stack出栈,不相等则继续入栈。stack每出栈一个元素,i下标后移一位,表示出栈。最后若stack为空,则返回true,否则返回false。
class Solution {
public boolean validateStackSequences(int[] pushed, int[] popped) {
Stack<Integer> stack = new Stack<>();
int i = 0,j=0;
while(j < pushed.length){
stack.push(pushed[j++]);
while(!stack.isEmpty() && stack.peek() == popped[i]){
stack.pop();
i++;
}
}
return stack.isEmpty();
}
}
本题用摩尔投票法,记超过一半的数字为“众数” res,票数为votes。
遍历一遍数组,如果票数为0,那么令res为当前遍历到的数字;票数不为0时,当前数字和res相等,则票数+1,不等则票数-1。最终得到的数字即为众数。
class Solution {
public int majorityElement(int[] nums) {
int res = 0, votes = 0;
for(int n:nums){
if(votes == 0) res = n;
votes += (res == n?1:-1);
}
return res;
}
}
本题的难点在于有两个数字只出现一次,我们都需要找出来。
首先我们将数组中的各个元素相互异或,结果就是这两个数字的异或,我们记为n。将此结果与数字1与,寻找两个数字二进制中不同的位m,接下来通过m将数组分为两组,每组只存在一个只出现一次的数字,分别找出来即可。
class Solution {
public int[] singleNumbers(int[] nums) {
int x = 0, y = 0;
int n = 0, m = 1;
for(int num:nums){
n^=num;
}
while((m&n) == 0){
m<<=1;
}
for(int num:nums){
if((num&m) == 0) x^=num;
else y^=num;
}
return new int[]{x,y};
}
}
题目中除了一个数字出现一次外,其他的数字都出现了三次,那么我们求得这个数组中的数字的每一位1的个数,对3求余就得到了我们想要数字的二进制表示,转化为int类型的数即可。
class Solution {
public int singleNumber(int[] nums) {
int[] arr = new int[32];
for(int n : nums){
int x = 1;
for(int i = 0;i<32;++i){
arr[i] += n&1;
n>>>=1;
}
}
int res = 0,m = 3;
for(int i = 0;i<32;++i){
res<<=1;
res |= arr[31-i]%m;
}
return res;
}
}
本题用双指针就可以求得结果,很简单。
class Solution {
public int[] twoSum(int[] nums, int target) {
int len = nums.length;
if(len < 2) return new int[0];
int[] res = new int[2];
int l = 0, r = len-1;
while(l < r){
if(nums[l] + nums[r] < target) l++;
else if(nums[l] + nums[r] > target) r--;
else{
res[0] = nums[l];
res[1] = nums[r];
return res;
}
}
return res;
}
}
代码参考LeetCode作者:Krahets