面试题51:数组中的逆序对





class Solution {
private:
const int kmod = 1000000007;
public:
int InversePairs(vector<int> data) {
int ret = 0;
int n = data.size();
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
if (data[i] > data[j]) {
ret += 1;
ret %= kmod;
}
}
}
return ret;
}
};


//取中间
int mid = (left + right) / 2;
//左右划分合并
merge(divide(left, mid, data, temp), divide(mid + 1, right, data, temp));



public class Solution {
public int mod = 1000000007;
public int mergeSort(int left, int right, int [] data, int [] temp){
//停止划分
if(left >= right)
return 0;
//取中间
int mid = (left + right) / 2;
//左右划分合并
int res = mergeSort(left, mid, data, temp) +
mergeSort(mid + 1, right, data, temp);
//防止溢出
res %= mod;
int i = left, j = mid + 1;
for(int k = left; k <= right; k++)
temp[k] = data[k];
for(int k = left; k <= right; k++){
if(i == mid + 1)
data[k] = temp[j++];
else if(j == right + 1 || temp[i] <= temp[j])
data[k] = temp[i++];
//左边比右边大,答案增加
else{
data[k] = temp[j++];
// 统计逆序对
res += mid - i + 1;
}
}
return res % mod;
}
public int InversePairs(int [] array) {
int n = array.length;
int[] res = new int[n];
return mergeSort(0, n - 1, array, res);
}
}

合并排序里面,这里代码很精简
for(int k = left; k <= right; k++){
if(i == mid + 1) data[k] = temp[j++];
else if(j == right + 1 || temp[i] <= temp[j]) data[k] = temp[i++];


面试题52: 两个链表的第一个公共节点







public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
ListNode l1 = pHead1, l2 = pHead2;
while(l1 != l2){
l1 = (l1==null)?pHead2:l1.next;
l2 = (l2==null)?pHead1:l2.next;
}
return l1;
}

import java.util.*;
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
//创建集合set
Setset = new HashSet<>();
//先把链表1的结点全部存放到集合set中
while (pHead1 != null) {
set.add(pHead1);
pHead1 = pHead1.next;
}
//然后访问链表2的结点,判断集合中是否包含链表2的结点,如果包含就直接返回
while (pHead2 != null) {
if (set.contains(pHead2))
return pHead2;
pHead2 = pHead2.next;
}
//如果集合set不包含链表2的任何一个结点,说明没有交点,直接返回null
return null;
}
}



面试题53:在排序数组中查找数字


暴力解法
public class Solution {
public int GetNumberOfK(int [] array , int k) {
int count = 0;
for(int i = 0; i < array.length; i++){
if(k == array[i]){
count++;
}
}
return count;
}
}



public class Solution {
//二分查找
private int bisearch(int[] data, double k){
int left = 0;
int right = data.length - 1;
//二分左右界
while(left <= right){
int mid = (left + right) / 2;
if(data[mid] < k)
left = mid + 1;
else if(data[mid] > k)
right = mid - 1;
}
return left;
}
public int GetNumberOfK(int [] array , int k) {
//分别查找k+0.5和k-0.5应该出现的位置,中间的部分就全是k
return bisearch(array, k + 0.5) - bisearch(array, k - 0.5);
}
}





class Solution {
public int missingNumber(int[] nums) {
//定义二分点,左右边界
int index, i = 0, j = nums.length-1;
//遍历
while(i < j){
index = (i + j) / 2;
//索引和值相等,在右边
if(nums[index] == index){
i = index + 1;
}
//索引和值不相等,在左边
else{
j = index - 1;
}
}
return i == nums[i] ? i+1: i;
}
}




//题目:假设一个单调递增的数组里的每个元素都是整数并且是唯一的。请编程实
//现一个函数找出数组中任意一个数值等于其下标的元素。例如,在数组{-3, -1,
//1, 3, 5}中,数字3和它的下标相等。
public class IntegerIdenticalToIndex {
public int getNumberSameAsIndex(int[] arr) {
//异常检测
if(arr==null || arr.length<=0)
return -1; //代表错误
int low=0;
int high=arr.length-1;
while(low<=high) {
int mid= (high+low)>>1;
if(arr[mid]>mid)
high=mid-1;
else if(arr[mid]<mid)
low=mid+1;
else
return mid;
}
return -1;
}
}
面试题54:二叉搜索树的第k大节点






/*
* public class TreeNode {
* int val = 0;
* TreeNode left = null;
* TreeNode right = null;
* public TreeNode(int val) {
* this.val = val;
* }
* }
*/
import java.util.*;
public class Solution {
//记录返回的节点
private TreeNode res = null;
//记录中序遍历了多少个
private int count = 0;
public void midOrder(TreeNode root, int k){
//当遍历到节点为空或者超过k时,返回
if(root == null || count > k)
return;
midOrder(root.left, k);
count++;
//只记录第k个
if(count == k)
res = root;
midOrder(root.right, k);
}
public int KthNode (TreeNode proot, int k) {
midOrder(proot, k);
if(res != null)
return res.val;
//二叉树为空,或是找不到
else
return -1;
}
}



面试题55:二叉树的深度







import java.util.*;
public class Solution {
public int maxDepth (TreeNode root) {
//空节点没有深度
if(root == null)
return 0;
//返回子树深度+1
return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}
}




import java.util.*;
public class Solution {
public int maxDepth (TreeNode root) {
//空节点没有深度
if(root == null)
return 0;
//队列维护层次后续节点
Queue<TreeNode> q = new LinkedList<TreeNode>();
//根入队
q.offer(root);
//记录深度
int res = 0;
//层次遍历
while(!q.isEmpty()){
//记录当前层有多少节点
int n = q.size();
//遍历完这一层,再进入下一层
for(int i = 0; i < n; i++){
TreeNode node = q.poll();
//添加下一层的左右节点
if(node.left != null)
q.offer(node.left);
if(node.right != null)
q.offer(node.right);
}
//深度加1
res++;
}
return res;
}
}



public class Solution {
public boolean IsBalanced_Solution(TreeNode root) {
if(root==null){
return true;
}
if(Math.abs(depth(root.left)-depth(root.right))>1){
return false;
}
return IsBalanced_Solution(root.left) && IsBalanced_Solution(root.right);
}
private int depth(TreeNode root){
if(root == null) return 0;
return Math.max(depth(root.left),depth(root.right))+1;
}
}



public class Solution {
boolean res = true;
public boolean IsBalanced_Solution(TreeNode root) {
isbalance(root);
return res;
}
public int isbalance(TreeNode root){
if(root == null || !res)
return 0;
int left = isbalance(root.left);
int right = isbalance(root.right);
if(Math.abs(left-right) > 1)
res = false;
return 1 + Math.max(left,right);
}
}

面试题56:数组中数字出现的次数



import java.util.*;
public class Solution {
public int[] FindNumsAppearOnce (int[] array) {
HashMap<Integer, Integer> mp = new HashMap<Integer, Integer>();
ArrayList<Integer> res = new ArrayList<Integer>();
//遍历数组
for(int i = 0; i < array.length; i++)
//统计每个数出现的频率
if(!mp.containsKey(array[i]))
mp.put(array[i], 1);
else
mp.put(array[i], mp.get(array[i]) + 1);
//再次遍历数组
for(int i = 0; i < array.length; i++)
//找到频率为1的两个数
if(mp.get(array[i]) == 1)
res.add(array[i]);
//整理次序
if(res.get(0) < res.get(1))
return new int[] {res.get(0), res.get(1)};
else
return new int[] {res.get(1), res.get(0)};
}
}





import java.util.*;
public class Solution {
public int[] FindNumsAppearOnce (int[] array) {
int res1 = 0;
int res2 = 0;
int temp = 0;
//遍历数组得到a^b
for(int i = 0; i < array.length; i++)
temp ^= array[i];
int k = 1;
//找到两个数不相同的第一位
while((k & temp) == 0)
k <<= 1;
for(int i = 0; i < array.length; i++){
//遍历数组,对每个数分类
if((k & array[i]) == 0)
res1 ^= array[i];
else
res2 ^= array[i];
}
//整理次序
if(res1 < res2)
return new int[] {res1, res2};
else
return new int[] {res2, res1};
}
}



解法一:哈希表
public static int singleNumber(int[] nums) {
HashMap<Integer, Integer> num = new HashMap<>();
//使用哈希映射统计数组中每个元素的出现次数。
//对于哈希映射中的每个键值对,键表示一个元素,值表示其出现的次数。
for (int key:nums) num.put(key,num.getOrDefault(key,0)+1);
//使用Map.Entry遍历num哈希表来获得只出现了一次的元素
for (Map.Entry<Integer, Integer> temp : num.entrySet()) {
// System.out.println("num key= " + temp.getKey() + " and value= " + temp.getValue());
if (temp.getValue() == 1)return temp.getKey();
}
return 0;
}
解法二:位运算的思路

//题目:在一个数组中除了一个数字只出现一次之外,其他数字都出现了三次。
//请找出那个只出现一次的数字。
public class NumberAppearingOnce {
public static int findNumberAppearingOnce(int[] arr) {
if(arr==null || arr.length<=0)
throw new RuntimeException();
int[] bitSum = new int[32];
//用0填充数组
for(int i=0;i<32;i++)
bitSum[i]=0;
for(int i=0;i<arr.length;i++) {
int bitMask=1;
for(int j=31;j>=0;j--) {
//注意arr[i]&bitMask不一定等于1或者0,有可能等于00010000
int bit=arr[i]&bitMask;
if(bit!=0)
//arr[i]此位置上也是1
bitSum[j]+=1;
bitMask=bitMask<<1;
}
}
int result=0;
for(int i=0;i<32;i++) {
result=result<<1;
result+=(bitSum[i]%3);
//result=result<<1; //不能放在后面,否则最前面一位就没了
}
return result;
}
}


面试题57:和为s的数字



暴力解法
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
ArrayList<Integer> result = new ArrayList<>();
for(int i = 0; i < array.length; i++){
for(int j = 0; j < array.length; j++){
if(i == j){
continue;
}
if(sum == (array[i] + array[j])){
result.add(array[i]);
result.add(array[j]);
return result;
}
}
}
return result;
}
}

时间复杂度 O(N*N),数据量太大的过不了

import java.util.*;
public class Solution {
public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
ArrayList<Integer> res = new ArrayList<Integer>();
//创建哈希表,两元组分别表示值、下标
HashMap<Integer, Integer> mp = new HashMap<Integer, Integer>();
//在哈希表中查找target-numbers[i]
for(int i = 0; i < array.length; i++){
int temp = sum - array[i];
//若是没找到,将此信息计入哈希表
if(!mp.containsKey(temp)){
mp.put(array[i], i);
}
else{
//取出数字添加
res.add(temp);
res.add(array[i]);
break;
}
}
return res;
}
}




import java.util.*;
public class Solution {
public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
ArrayList<Integer> res = new ArrayList<Integer>();
//左右双指针
int left = 0, right = array.length - 1;
//对撞双指针
while(left < right){
//相加等于sum,找到目标
if(array[left] + array[right] == sum){
res.add(array[left]);
res.add(array[right]);
break;
//和太大,缩小右边
}else if(array[left] + array[right] > sum)
right--;
//和太小,扩大左边
else
left++;
}
return res;
}
}





这部分等看了左程云的视频课再来看

class Solution {
public int[][] findContinuousSequence(int target) {
int i=1, j=1;//窗口左右边界
int sum=0;//用来与target比较
List<int[]> list=new ArrayList<>();//结果集合
while(i<=target/2) {
if(sum < target) {
sum+=j;
j++;
} else if(sum > target) {
sum-=i;
i++;
} else {
int[] arr=new int[j-i];
for(int k=i;k<j;k++) {
arr[k-i]=k;
}
list.add(arr);
//记录一个结果之后,一定记得窗口右移
sum-=i;
i++;
}
}
int[][] T=new int[list.size()][];
return list.toArray(T);
}
}

面试题58:翻转字符串


public class Solution {
public String ReverseSentence(String str) {
String[] arr = str.split(" ");
String[] result = new String[arr.length];
for (int i = arr.length - 1; i >= 0; i--) {
result[arr.length - 1 - i] = arr[i];
}
StringBuffer sb = new StringBuffer();
for (int i = 0; i < result.length; i++) {
if (i != result.length - 1) {
sb.append(result[i]);
sb.append(" ");
} else {
sb.append(result[i]);
}
}
return sb.toString();
}
}



import java.util.*;
public class Solution {
//字符串反转函数
private void reverse(char [] c, int l, int h){
//双指针反转
while(l < h)
swap(c, l++, h--);
}
//字符交换函数
private void swap(char [] c, int l, int h){
char temp = c[l];
c[l] = c[h];
c[h] = temp;
}
public String ReverseSentence(String str) {
int n = str.length();
char[] c = str.toCharArray();
//第一次整体反转
reverse(c, 0, n - 1);
for(int i = 0; i < n; i++){
int j = i;
//以空格为界找到一个单词
while(j < n && c[j] != ' ')
j++;
//将这个单词反转
reverse(c, i, j - 1);
i = j;
}
return new String(c);
}
}




import java.util.*;
public class Solution {
public String ReverseSentence(String str) {
Stack<String> st = new Stack<String>();
String[] temp = str.split(" ");
//单词加入栈中
for(int i = 0; i < temp.length; i++){
st.push(temp[i]);
st.push(" ");
}
StringBuilder res = new StringBuilder();
//去掉最后一个空格
if(!st.isEmpty())
st.pop();
//栈遵循先进后出,单词顺序是反的
while(!st.isEmpty())
res.append(st.pop());
return res.toString();
}
}







public class Solution {
public String LeftRotateString(String str,int n) {
//取余,因为每次长度为n的旋转数组相当于没有变化
if(str.isEmpty() || str.length() == 0)
return "";
int m = str.length();
n = n % m;
//第一次逆转全部元素
char[] s = str.toCharArray();
reverse(s, 0, m - 1);
//第二次只逆转开头m个
reverse(s, 0, m - n - 1);
//第三次只逆转结尾m个
reverse(s, m - n, m - 1);
return new String(s);
}
//反转函数
private void reverse(char[] s, int start, int end){
while(start < end){
swap(s, start++, end--);
}
}
//交换函数
private void swap(char[] s, int a, int b){
char temp = s[a];
s[a] = s[b];
s[b] = temp;
}
}


import java.util.*;
public class Solution {
public String LeftRotateString(String str,int n) {
//取余,因为每次长度为n的旋转数组相当于没有变化
if(str.isEmpty() || str.length() == 0)
return "";
int m = str.length();
//取余,因为每次长度为m的旋转数组相当于没有变化
n = n % m;
StringBuilder res = new StringBuilder();
//先遍历后面的,放到前面
for(int i = n; i < m; i++)
res.append(str.charAt(i));
//再遍历前面的放到后面
for(int i = 0; i < n; i++)
res.append(str.charAt(i));
return res.toString();
}
}


面试题59:队列的最大值




暴力解法:
import java.util.*;
public class Solution {
public ArrayList<Integer> maxInWindows(int [] num, int size) {
ArrayList<Integer> result = new ArrayList<Integer>();
int max = Integer.MIN_VALUE;
//异常检测
if (num == null || num.length == 0 || size == 0) {
return result;
}
//暴力解法
for (int i = 0; i < num.length - size + 1; i++) {
for (int j = i; j - i < size; j++) {
if (max < num[j]) {
max = num[j];
}
}
result.add(max);
max = Integer.MIN_VALUE;
}
return result;
}
}
时间复杂度为:O(N*K)

class Solution {
public:
vector<int> maxInWindows(const vector<int>& num, unsigned int size)
{
// Vector类 是在 java 中可以实现自动增长的对象数组
vector<int> ret;
if (num.size() == 0 || size < 1 || num.size() < size) return ret;
int n = num.size();
for (int i = 0; i + size - 1 < n; ++i) {
int j = i + size - 1;
int max_val = num[j];
for (int k = i; k < j; ++k) {
max_val = max(max_val, num[k]);
}
ret.push_back(max_val);
}
return ret;
}
};


class Solution {
public:
vector<int> maxInWindows(const vector<int>& num, unsigned int size)
{
vector<int> ret;
if (num.size() == 0 || size < 1 || num.size() < size) return ret;
int n = num.size();
deque<int> dq;
for (int i = 0; i < n; ++i) {
//dq.back() dq 最后一个元素索引
while (!dq.empty() && num[dq.back()] < num[i]) {
//弹出并删除 dq 最后一个元素
dq.pop_back();
}
//添加到 dq 末尾
dq.push_back(i);
// 判断队列的头部的下标是否过期
//dq.front() 第一个元素的索引
if (dq.front() + size <= i) {
//弹出并删除 dq 第一个元素
dq.pop_front();
}
// 判断是否形成了窗口
if (i + 1 >= size) {
//如果形成了窗口,将该窗口最大值添加到结果数组中
ret.push_back(num[dq.front()]);
}
}
return ret;
}
};

简述Java中的Deque<E>(双端队列)接口
1 定义
Interface Deque<E>:继承了Queue接口,支持两端元素插入和移除的线性集合。
2 特性
既具有队列FIFO(先进先出)特点又具有栈LIFO(后进先出)特点,既是队列又是栈。
3 常用方法
public void offerFirst(E e):向队头插入元素
public void offerLast(E e):向队尾插入元素
public E pollFirst():获取并移除队头元素
public E pollLast():获取并移除队尾元素
public E peekFirst():获取队头元素
public E peekLast():获取队尾元素
public int size():获取队列中的元素个数
4 栈操作
队头插入队头删除(后进先出):
public void push(E e) :向队头插入元素
public E pop() :检索并删除队头元素
public E peek():检索但不删除队头元素
5 队列操作
队尾插入队头删除(先进先出):
boolean offer(E e):向队尾插入元素
public E poll() :检索并删除队头元素
public E peek():检索但不删除队头元素
6 两个主要实现类
ArrayDeque: 基于数组实现的线性双端队列;
LinkedList: 基于链表实现的链式双端队列。




class MaxQueue {
int[] q = new int[20000];
int begin = 0, end = 0;
public MaxQueue() {
}
public int max_value() {
int ans = -1;
for (int i = begin; i != end; ++i) {
ans = Math.max(ans, q[i]);
}
return ans;
}
public void push_back(int value) {
q[end++] = value;
}
public int pop_front() {
if (begin == end) {
return -1;
}
return q[begin++];
}
}


class MaxQueue {
Queue<Integer> q;
Deque<Integer> d;
public MaxQueue() {
q = new LinkedList<Integer>();
d = new LinkedList<Integer>();
}
public int max_value() {
if (d.isEmpty()) {
return -1;
}
return d.peekFirst();
}
//往队列末尾插入元素
public void push_back(int value) {
while (!d.isEmpty() && d.peekLast() < value) {
d.pollLast();
}
d.offerLast(value);
q.offer(value);
}
public int pop_front() {
if (q.isEmpty()) {
return -1;
}
int ans = q.poll();
if (ans == d.peekFirst()) {
d.pollFirst();
}
return ans;
}
}


面试题60:n个骰子的点数











class Solution {
public double[] dicesProbability(int n) {
double[] dp = new double[6];
Arrays.fill(dp, 1.0 / 6.0);
for (int i = 2; i <= n; i++) {
double[] tmp = new double[5 * i + 1];
for (int j = 0; j < dp.length; j++) {
for (int k = 0; k < 6; k++) {
tmp[j + k] += dp[j] / 6.0;
}
}
dp = tmp;
}
return dp;
}
}