package com.dengzm.jianzhioffer;
/**
* @Description 049 丑数
* 我们把只包含因子2,3和5的数称作丑数。求按从大到小的第1500个丑数
*
* Created by deng on 2019/9/22.
*/
public class Jianzhi049 {
public static void main(String[] args) {
System.out.println(getUglyNumber(1));
System.out.println(getUglyNumber(10));
System.out.println(getUglyNumber(100));
System.out.println(getUglyNumber(1500));
}
private static int getUglyNumber(int index) {
if (index <= 0) {
return 0;
}
int[] uglyNumbers = new int[index];
uglyNumbers[0] = 1;
int nextUglyNumberIndex = 1;
int mutiply2 = 0;
int mutiply3 = 0;
int mutiply5 = 0;
while (nextUglyNumberIndex < index) {
int num = Math.min(Math.min(uglyNumbers[mutiply2] * 2, uglyNumbers[mutiply3] * 3), uglyNumbers[mutiply5] * 5);
uglyNumbers[nextUglyNumberIndex] = num;
while (uglyNumbers[mutiply2] * 2 <= uglyNumbers[nextUglyNumberIndex]) {
mutiply2 ++;
}
while (uglyNumbers[mutiply3] * 3 <= uglyNumbers[nextUglyNumberIndex]) {
mutiply3 ++;
}
while (uglyNumbers[mutiply5] * 5 <= uglyNumbers[nextUglyNumberIndex]) {
mutiply5 ++;
}
nextUglyNumberIndex ++;
}
return uglyNumbers[index - 1];
}
}
package com.dengzm.jianzhioffer;
import java.util.HashMap;
/**
* @Description 050 第一个只出现一次的字符
*
* Created by deng on 2019/9/22.
*/
public class Jianzhi050 {
public static void main(String[] args) {
String data1 = "asdjbj!)kvbklasdk@%^*&^#&*lvka";
String data2 = "qwertyuiopasdfghjkqwertyuiopasdfghjkl!";
String data3 = "qwertyuiopasdfghjkqwertyuiopasdfghjk";
System.out.println(findFirstNoRepeatChar(data1));
System.out.println(findFirstNoRepeatChar(data2));
System.out.println(findFirstNoRepeatChar(data3));
}
private static String findFirstNoRepeatChar(String target) {
if (target == null || target.length() == 0) {
throw new RuntimeException("sth is wrong with target string");
}
char[] targetChars = target.toCharArray();
HashMap<Character, Integer> repeatNumbers = new HashMap<>();
for (int i = 0; i < targetChars.length; i ++) {
if (repeatNumbers.containsKey(targetChars[i])) {
repeatNumbers.put(targetChars[i], repeatNumbers.get(targetChars[i]) + 1);
} else {
repeatNumbers.put(targetChars[i], 1);
}
}
for (int i = 0; i < targetChars.length; i ++) {
int number = repeatNumbers.get(targetChars[i]);
if (number == 1) {
return String.valueOf(targetChars[i]);
}
}
return "there is no NonRepeating char in target string : " + target;
}
}
package com.dengzm.lib;
/**
* @Description 051 数组中的逆序对
* 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求逆序对的总数
* 例如:数组{7,5,6,4}中有5个逆序对,分别为{7,6}, {7,5}, {7,4}, {6,4}, {5,4}
*
* Created by deng on 2019/9/22.
*/
public class Jianzhi051 {
public static void main(String[] args) {
int[] data1 = new int[] {7, 5, 6, 4};
int[] data2 = new int[] {7, 5, 6, 4, 8, 1};
int[] data3 = new int[] {7, 5, 6, 4, 1};
int[] data4 = new int[] {7, 5, 6, 4, 10, 5, 4, 19, 2};
System.out.println("inverse pairs num is " + countInversePairs(data1));
System.out.println("inverse pairs num is " + countInversePairs(data2));
System.out.println("inverse pairs num is " + countInversePairs(data3));
System.out.println("inverse pairs num is " + countInversePairs(data4));
}
/**
* 通过归并排序的方式进行统计
* 拆分data,合并时对逆序对进行统计
*
* @param data data
* @return num of inverse pairs
*/
private static int countInversePairs(int[] data) {
if (data == null || data.length == 0) {
return 0;
}
// 复制数组,不直接使用原始数据
int[] copy = new int[data.length];
System.arraycopy(data, 0, copy, 0, data.length);
return countInversePairsCore(copy, 0, data.length - 1);
}
private static int countInversePairsCore(int[] copy, int start, int end) {
if (start >= end) {
return 0;
}
int length = (end - start) / 2;
int left = countInversePairsCore(copy, start, start + length);
int right = countInversePairsCore(copy, start + length + 1, end);
// 初始化前后半段的最后一个数字的下标
int i = start + length;
int j = end;
// 临时数据
int[] temp = new int[end - start + 1];
// 临时数据的下标
int indexCopy = end - start;
// return result
int count = 0;
// 归并-合并时,如果前段大于后段,则增加count,因为前后半段各自都是递增的,所以增加的数量为end - mid
while (i >= start && j >= start + length + 1) {
if (copy[i] > copy[j]) {
temp[indexCopy --] = copy[i --];
count += j - start - length;
} else {
temp[indexCopy --] = copy[j --];
}
}
// 将剩余数据复制到临时数据
while (i >= start) {
temp[indexCopy --] = copy[i --];
}
while (j >= start + length + 1) {
temp[indexCopy --] = copy[j --];
}
// 将临时数据同步回copy,保证合并后的数据为递增
System.arraycopy(temp, 0, copy, start, temp.length);
return left + right + count;
}
}
package com.dengzm.jianzhioffer;
/**
* @Description 052 两个链表的第一个公共节点
*
* Created by deng on 2019/9/22.
*/
public class Jianzhi052 {
public static void main(String[] args) {
Node node1 = new Node(1);
Node node2 = new Node(2);
Node node3 = new Node(3);
Node node4 = new Node(4);
Node node5 = new Node(5);
Node node6 = new Node(6);
Node node7 = new Node(7);
node1.next = node2;
node2.next = node3;
node3.next = node6;
node6.next = node7;
node4.next = node5;
node5.next = node6;
Node result = findFirstSameNode(node1, node4);
System.out.println(result == null ? "null" : result.value);
}
private static Node findFirstSameNode(Node head1, Node head2) {
if (head1 == null || head2 == null) {
return null;
}
int difLength;
Node longHead;
Node shortHead;
int length1 = getLength(head1);
int length2 = getLength(head2);
if (length1 > length2) {
longHead = head1;
shortHead = head2;
difLength = length1 - length2;
} else {
longHead = head1;
shortHead = head2;
difLength = length1 - length2;
}
if (difLength != 0) {
for (int i = 0; i < difLength; i ++) {
longHead = longHead.next;
}
}
while (longHead != null && shortHead != null) {
if (longHead == shortHead) {
return longHead;
}
longHead = longHead.next;
shortHead = shortHead.next;
}
return null;
}
private static int getLength(Node head) {
int len = 0;
Node temp = head;
while(temp != null) {
len ++;
temp = temp.next;
}
return len;
}
private static class Node {
int value;
Node next;
Node(int value) {
this.value = value;
}
}
}
package com.dengzm.lib;
/**
* @Description 053 在排序数组中查找数字
* 题目一:数字在排序数组中出现的次数
* 题目二:0~n-1中缺失的数字
* 题目三:数组中数值和下标相等的元素:假设一个单调递增的数组里的每个元素都是整数并且唯一,请实现一个函数可以找出数组中任意一个数值等于其下标的元素
*
* Created by deng on 2019/10/29.
*/
public class Jianzhi053 {
public static void main(String[] args) {
int[] data1 = new int[] {1, 2, 3, 3, 3, 3, 4, 6};
int[] data2 = new int[] {1, 2, 3, 3, 3, 3, 4, 4, 6, 7, 8};
int[] data3 = new int[] {1, 2, 3, 3, 3, 3, 4, 6};
int[] data4 = new int[] {0, 1, 2, 3, 4, 6, 7, 8, 9};
int[] data5 = new int[] {0, 2};
int[] data6 = new int[] {1};
int[] data7 = new int[] {-3, -1, 0, 2, 4, 6, 8};
int[] data8 = new int[] {-3, 1};
int[] data9 = new int[] {0};
int[] data10 = new int[] {-3};
System.out.println("Q1:number of 3 in data1 is " + getNumberOfK(data1, 3));
System.out.println("Q1:number of 4 in data2 is " + getNumberOfK(data2, 4));
System.out.println("Q1:number of 4 in data3 is " + getNumberOfK(data3, 4));
System.out.println("Q2:lost number in data4 is " + getLostNum(data4));
System.out.println("Q2:lost number in data5 is " + getLostNum(data5));
System.out.println("Q2:lost number in data6 is " + getLostNum(data6));
System.out.println("Q3:the num of which is equal to its index in data7 is " + getNumEqualToIndex(data7));
System.out.println("Q3:the num of which is equal to its index in data8 is " + getNumEqualToIndex(data8));
System.out.println("Q3:the num of which is equal to its index in data9 is " + getNumEqualToIndex(data9));
System.out.println("Q3:the num of which is equal to its index in data10 is " + getNumEqualToIndex(data10));
}
/**
* 题目一
* 通过二分法,找到数字k的第一个位置和最后一个的位置
* 时间复杂度 O(logn)
*
* @param data data
* @param k the num we are looking for
* @return how many k in data
*/
private static int getNumberOfK(int[] data, int k) {
if (data == null || data.length == 0) {
return 0;
}
int first = getFirstK(data, k, 0, data.length - 1);
int last = getLastK(data, k, 0, data.length - 1);
return first == -1 ? 0 : last - first + 1;
}
private static int getFirstK(int[] data, int k, int start, int end) {
if (start > end) {
return -1;
}
int middleIndex = (end + start) / 2;
int middleData = data[middleIndex];
if (middleData == k) {
// 当前数字为k,开始判断是否为第一个k
if (middleIndex == 0 || (middleIndex > 0 && data[middleIndex - 1] != k)) {
// 当前位置下标为0 或 前一个数字不是k
// 表示此时得到的下标即为第一个k
return middleIndex;
} else {
// 下标不为0,且前一个数字为k,在前半段中再次进行二分查找
end = middleIndex - 1;
}
} else {
// 当前数字不为k,进行判断,在前后半段中的哪一个
if (middleData > k) {
end = middleIndex - 1;
} else {
start = middleIndex + 1;
}
}
return getFirstK(data, k, start, end);
}
private static int getLastK(int[] data, int k, int start, int end) {
if (start > end) {
return -1;
}
int middleIndex = (end + start) / 2;
int middleData = data[middleIndex];
if (middleData == k) {
// 当前数字为k,开始判断是否为最后一个k
if (middleIndex == data.length - 1 || (middleIndex < data.length - 1 && data[middleIndex + 1] != k)) {
// 当前位置下标为length-1 或 后一个数字不是k
// 表示此时得到的下标即为最后一个k
return middleIndex;
} else {
// 下标不为length-1,且后一个数字为k,在后半段中再次进行二分查找
start = middleIndex + 1;
}
} else {
// 当前数字不为k,进行判断,在前后半段中的哪一个
if (middleData > k) {
end = middleIndex - 1;
} else {
start = middleIndex + 1;
}
}
return getLastK(data, k, start, end);
}
/**
* 题目二
* 0~n-1,数字大小与下标相同
* 使用二分法进行查找,找到第一个下标与数字不等的位置,即为缺失的数字
*
* @param data data
* @return the lost num
*/
private static int getLostNum(int[] data) {
if (data == null || data.length == 0) {
return -1;
}
int left = 0;
int right = data.length - 1;
while (left <= right) {
int middle = (left + right) / 2;
// 当mid的下标与数字不等时,如果前一个相等,或是mid为0,则当前mid即为缺失的数字;否则继续在前半段查找
if (data[middle] != middle) {
if (middle == 0 || (data[middle - 1] == middle - 1)) {
return middle;
} else {
right = middle - 1;
}
} else {
// 下标相等时,在后半段查找
left = middle + 1;
}
}
return -1;
}
/**
* 题目三
* 二分法查找:如果num > index,则在前半段查找;如果num < index, 则在后半段查找
*
* @param data data
* @return num of which is equal to its index
*/
private static int getNumEqualToIndex(int[] data) {
if (data == null || data.length == 0) {
return -1;
}
int left = 0;
int right = data.length - 1;
while (left <= right) {
int middle = (left + right) / 2;
if (data[middle] == middle) {
return middle;
} else if (data[middle] < middle) {
// num < index, 则在后半段查找
left = middle + 1;
} else {
// num > index,则在前半段查找
right = middle - 1;
}
}
return -1;
}
}