1-多数元素
题目链接:题目链接戳这里!!!
思路1:因为多数元素就一个,直接升序排序,返回中间那个值,一定是升序元素。
class Solution {
public int majorityElement(int[] nums) {
Arrays.sort(nums) ;
return nums[nums.length/2];
}
}
思路2:借助HashMap,存储每个数字出现的次数,出现次数大于n/2,则该数字就是多数元素。
class Solution {
public int majorityElement(int[] nums) {
Map<Integer, Integer> map = new HashMap<>() ;
int mid = nums.length / 2 ;
for(int i=0; i<nums.length; i++){
int count = map.getOrDefault(nums[i],0)+1 ;
if(count>mid){
return nums[i];
}
map.put(nums[i],count) ;
}
return nums[nums.length-1] ;
}
}
因为我们要找的是多数元素,那么我们将数组分成两部分,则至少有一部分的多数元素和数组的多数元素相同,那么这样,我们就可以用分治的思想了,递归求出左半数组的多数元素和右半数组的多数元素,如果二者相同,则该数就是数组的多数元素,如果不同,需要比较二者在数组中出现的次数,出现次数多的为多数元素。
AC代码如下:
class Solution {
public int majorityElement(int[] nums) {
return split(nums, 0, nums.length-1) ;
}
public int split(int [] nums, int left, int right){
if(left==right){
return nums[left] ;
}
int mid = (left+right)>>1 ;
int leftMajor = split(nums,left,mid) ;
int rightMajor = split(nums,mid+1,right) ;
if(leftMajor==rightMajor){
return leftMajor ;
}
return merge(nums, leftMajor, rightMajor, left, right) ;
}
public int merge(int [] nums, int leftMajor, int rightMajor, int left, int right){
int countLeft = 0, countRight = 0 ;
for(int i=left; i<=right; i++){
if(nums[i]==leftMajor){
countLeft ++ ;
}
if(nums[i]==rightMajor){
countRight ++ ;
}
}
return Math.max(countRight,countLeft)==countLeft ? leftMajor : rightMajor ;
}
}
2-寻找两个正序数组中的中位数
题目链接:题目链接戳这里!!!
思路1:直接合并为一个数组,升序排序,找出中位数即可。该方法虽然能AC,但是时间复杂度O(n)。
AC代码如下:
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int m = nums1.length ;
int n = nums2.length ;
int [] arr = new int [m+n] ;
for(int i=0; i<m; i++){
arr[i] = nums1[i] ;
}
for(int i=m; i<m+n; i++){
arr[i] = nums2[i-m] ;
}
Arrays.sort(arr) ;
if((arr.length&1) == 1){
return arr[(m+n)/2] ;
}else{
return 1.0 * (arr[(m+n)/2]+arr[(m+n)/2-1]) / 2 ;
}
}
}
3- 数组中的第K个最大元素
题目链接:题目链接戳这里!!!
思路1:直接调库排序,然后输出第K大的就可以。这个效率已经很高了。
class Solution {
public int findKthLargest(int[] nums, int k) {
Arrays.sort(nums) ;
return nums[nums.length - k] ;
}
}
快排是基于分治的思想,将数组分成两部分,将大于主元的放在右边,小于主元的放到左边,然后对左右进行递归排序,如果主元的下标等于nums.length-k则说明找到了,否则根据主元的位置,对左边数组或者右边数组继续排序。
效率杠杠滴!!!
class Solution {
public int findKthLargest(int[] nums, int k) {
return quickSort(nums, 0, nums.length-1, nums.length-k) ;
}
public int quickSort(int []nums, int left, int right, int idx){
int q = partition(nums, left, right) ;
if(q>idx){
return quickSort(nums,0,q-1,idx) ;
}else if(q<idx){
return quickSort(nums,q+1,right,idx) ;
}else{
return nums[idx] ;
}
}
public int partition(int [] arr, int p, int r){
int idx = (int) (Math.random()*(r-p+1)) + p ;
swap(arr, idx, p) ;
int pivot = arr[p] ; //初始化主元
int left = p + 1; //左侧扫描指针
int right = r ; //右侧扫描指针
while(left <= right){
while(left <= right && arr[left] <= pivot){
left ++ ;
}
while(left <= right && arr[right] >= pivot){
right -- ;
}
if(left < right){ //找到左侧比主元大的,右侧比主元小的,二者交换
swap(arr, left, right) ;
}
}
swap(arr, p, right) ; //将初始化的主元与划分后得到的主元交换
return right ;
}
public void swap(int []arr, int i, int j){
int temp = arr[i] ;
arr[i] = arr[j] ;
arr[j] = temp ;
}
}
4-摆动序列II
题目链接:题目链接戳这里!!!
思路:直接采用插孔的方式,先升序排序,然后然后从从往前选元素,依次插孔。
class Solution {
public void wiggleSort(int[] nums) {
Arrays.sort(nums) ;
int [] array = new int [nums.length] ;
int k=nums.length-1;
for(int i=1;i<nums.length;i+=2)
{
array[i]=nums[k--];
}
for(int i=0;i<nums.length;i+=2)
{
array[i]=nums[k--];
}
for(int i=0; i<array.length; i++){
nums[i] = array[i] ;
}
}
}
思路:分为跨边界和没有跨边界两种情况。
如果没有跨界,依次遍历,找出最大和即可。
如果跨边界,需要记录总和减取最小和。
AC代码如下:
class Solution {
public int maxSubarraySumCircular(int[] nums) {
//分为跨边界和没跨边界两种情况
int curMin, curMax, min, max, sum ;
curMax = curMin = max = min = sum = nums[0] ;
for(int i=1; i<nums.length; i++){
sum += nums[i] ;
curMax = curMax>0 ? curMax+nums[i] : nums[i] ;
max = Math.max(max, curMax) ;
curMin = curMin<0 ? curMin+nums[i] : nums[i] ;
min = Math.min(min, curMin) ;
}
if(max<0){
return max ;
}
return Math.max(max, sum-min) ;
}
}
思路1:用HashMap记录每个数字出现的次数,找到出现次数最多的,再通过HashMap依次对比输出出现次数前K多的元素即可。
AC代码如下:
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer,Integer> map = new HashMap<>() ;
for(int i=0; i<nums.length; i++){
map.put(nums[i],map.getOrDefault(nums[i],0)+1) ;
}
int maxTimes = 0 ;
for(Map.Entry<Integer,Integer> entry : map.entrySet()){
if(entry.getValue()>=maxTimes){
maxTimes = entry.getValue() ;
}
}
int [] res = new int [k] ;
while(k>0){
for(Map.Entry<Integer,Integer> entry : map.entrySet()){
if(entry.getValue()==maxTimes){
res[k-1] = entry.getKey();
k -- ;
}
}
maxTimes -- ;
}
return res ;
}
}
思路如图所示,不过是把大的放到arr[q]左面,小的放到arr[q]右面.
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer,Integer> map = new HashMap<>() ;
for(int i=0; i<nums.length; i++){
map.put(nums[i],map.getOrDefault(nums[i],0)+1) ;
}
List<int[]> list = new ArrayList<>() ;
for(Map.Entry<Integer,Integer> entry : map.entrySet()){
list.add(new int[]{entry.getKey(),entry.getValue()}) ;
}
int [] res = new int [k] ;
quickSort(list, 0, list.size()-1, res, 0, k) ;
return res ;
}
public void quickSort(List<int[]>list, int start, int end, int [] res, int resIndex, int k){
int p = (int)(Math.random()*(end-start+1)) + start ;
Collections.swap(list,p,start) ;
int pivot = list.get(start)[1] ;
int idx = start ;
for(int i=start+1; i<=end; i++){
if(list.get(i)[1]>=pivot){
Collections.swap(list,i,idx+1) ;
idx ++ ;
}
}
Collections.swap(list, start, idx) ;
if(k <=idx-start){
quickSort(list, start, idx-1, res, resIndex, k) ;
}else{
for(int i=start; i<=idx; i++){
res[resIndex++] = list.get(i)[0] ;
}
if(k>idx-start+1){
quickSort(list,idx+1, end, res, resIndex, k-(idx-start+1)) ;
}
}
}
}