本文按照牛客网的顺序,牛客网剑指offer刷题网址:https://www.nowcoder.com/ta/coding-interviews
本篇涉及的题目有:
1、数组中出现次数超过一半的数字
2、最小的K个数
3、连续子数组的最大和
4、把数组排成最小的数
5、丑数
6、数组中的逆序对
1、数组中出现次数超过一半的数字
问题描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
思路解析
假设有数字超过数组长度的一半,我们使用一个计数器,如果该数字出现一次,计数器加一,如果不是该数字,计数器减一,那么到最后,计数器一定是大于0的。那么我们可以按照如下的规则:我们首先假设最终的结果是数组的第一个数,计数器初始为1。从第二个数开始遍历,如果与当前的数相同,计数器加1,如果不同,判断计数器的状态,如果大于0,则减一;如果等于零,则置1。同时将假设的最终结果变为当前的数。
这里最后要判断最后的结果是不是真的出现了一半以上的次数。
代码实现
java
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
if(array.length==0)
return 0;
int res = array[0];
int count = 1;
for(int i=1;iarray.length / 2)
return res;
else
return 0;
}
}
python
# -*- coding:utf-8 -*-
class Solution:
def MoreThanHalfNum_Solution(self, numbers):
# write code here
res = numbers[0]
count = 1
for num in numbers[1:]:
if num == res:
count = count + 1
else:
if count == 0:
res = num
count = 1
else:
count = count - 1
count = 0
for num in numbers:
if num == res:
count = count + 1
if count > len(numbers) / 2:
return res
else:
return 0
2、最小的K个数
问题描述
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
思路解析
使用堆排序,找到最小的K个数。
代码实现
java
import java.util.*;
public class Solution {
public ArrayList GetLeastNumbers_Solution(int [] input, int k) {
ArrayList arr=new ArrayList();
int len=input.length;
if(k>len)
return arr;
for(int i=0;i=i;j--){
int p=(j+i-1)/2;
if(input[p]>input[j]){
int temp=input[p];
input[p]=input[j];
input[j]=temp;
}
}
}
}
python
# -*- coding:utf-8 -*-
class Solution:
def GetLeastNumbers_Solution(self, tinput, k):
# write code here
if len(tinput) < k or k==0:
return []
self.buildHeap(tinput[:k],k)
for i in range(k,len(tinput)):
if tinput[i] > self.heap[0]:
continue
else:
self.heap[0] = tinput[i]
self.perceDown(0,k)
return sorted(self.heap)
def buildHeap(self,tinput,k):
self.heap = tinput
for i in range(k//2,-1,-1):
self.perceDown(i,k)
def perceDown(self,i,k):
temp = self.heap[i]
while (2 * i + 1) < k:
child = 2 * i + 1
if (child < k - 1) and self.heap[child] < self.heap[child+1]:
child = child + 1
if temp < self.heap[child]:
self.heap[i] = self.heap[child]
i = child
else:
break
self.heap[i] = temp
3、连续子数组的最大和
问题描述
HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。你会不会被他忽悠住?(子向量的长度至少是1)
思路解析
这道题跟之前我在网易面试的股票买卖问题类似,采用的叫Kadane's Algorithm的方法,用两个指针。maxSum指针记录此前所有碰到的最大值,curSum指针记录循环到当前元素这一轮的最大值。当循环到元素i时,如果i+curSum < i的话,说明此前的和是负的,需要舍弃,所以将curSum的值变为i,反之,将curSum的值变为i+curSum,表明当前的和还是正值,可以继续向前探索,由于每一次遍历一个元素之后都会比较一下curSum和maxSum,所以可以放心的继续向前遍历。
代码实现
java
public class Solution {
public int FindGreatestSumOfSubArray(int[] array) {
if(array.length==0)
return 0;
int maxCur = array[0];
int maxSoFar = array[0];
for(int i = 1;i
python
# -*- coding:utf-8 -*-
class Solution:
def FindGreatestSumOfSubArray(self, array):
# write code here
maxCur = array[0]
maxSoFar = array[0]
for t in array[1:]:
maxCur = max(t,maxCur + t)
maxSoFar = max(maxSoFar,maxCur)
return maxSoFar
4、把数组排成最小的数
问题描述
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
思路解析
这道题其实希望我们能够找到一个排序规则,数组根据这个规则排序之后能排成一个最小的数字。要确定排序的规则,就要比较两个数字,也就是给出两个数字m和n,我们需要确定一个规则判断m和n哪个应该排在前面,而不是仅仅比较这两个数字的值哪个更大。
根据题目的要求,两个数字m和n能拼接称数字mn和nm。如果mn 代码实现 python 问题描述 思路解析 代码实现 python 问题描述 思路解析 代码实现 python
javaimport java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class Solution {
public String PrintMinNumber(int [] numbers) {
int n;
String s="";
ArrayList
# -*- coding:utf-8 -*-
class Solution:
def PrintMinNumber(self, numbers):
# write code here]
if not len(numbers):
return ""
arr = [str(x) for x in numbers]
arr.sort(lambda x,y:cmp(x+y,y+x))
return int("".join(arr))
5、丑数
把只包含因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
暴力求解丑数是不可行的,使用动态规划的解法,首先我们要确保数组里的已有的丑数是排好序的,同时要维护三个索引。
javaimport java.util.*;
public class Solution {
public int GetUglyNumber_Solution(int index) {
if(index == 0)
return 0;
int index2 = 0;
int index3 = 0;
int index5 = 0;
ArrayList
# -*- coding:utf-8 -*-
class Solution:
def GetUglyNumber_Solution(self, index):
# write code here
if index<=0:
return 0
res = [1]
index2 = 0
index3 = 0
index5 = 0
while(len(res) < index):
nextMin = min(res[index2] * 2,res[index3] * 3,res[index5] * 5)
res.append(nextMin)
while res[index2] * 2 <= nextMin:
index2 = index2 + 1
while res[index3] * 3 <= nextMin:
index3 = index3 + 1
while res[index5] * 5 <= nextMin:
index5 = index5 + 1
return res[-1]
6、数组中的逆序对
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
使用归并排序的思路进行求解
javaimport java.io.*;
import java.util.*;
public class Main {
public static int InversePairs(int [] array) {
if(array==null||array.length==0)
{
return 0;
}
int[] copy = new int[array.length];
for(int i=0;i
# -*- coding:utf-8 -*-
class Solution:
def InversePairs(self, data):
# write code here
if len(data) > 1:
mid = len(data) / 2
left_half = data[:mid]
right_half = data[mid:]
left_count = self.InversePairs(left_half)%1000000007
right_count = self.InversePairs(right_half)%1000000007
i,j,k,count = len(left_half)-1,len(right_half)-1,len(data)-1,0
while i >= 0 and j >= 0:
if left_half[i] < right_half[j]:
data[k] = right_half[j]
j = j - 1
k = k - 1
else:
data[k] = left_half[i]
count += (j+1)
i = i - 1
k = k - 1
while i >= 0:
data[k] = left_half[i]
k = k - 1
i = i - 1
while j>=0:
data[k] = right_half[j]
k = k - 1
j = j - 1
return (count + left_count + right_count)%1000000007
else:
return 0