1、自己答案
/**
* @param A: An integer array
* @return: An integer
*/
public int singleNumber(int[] A) {
Set<Integer> set = new HashSet<>();
for (int i = 0;i<A.length ;i++ ){
boolean flag = set.add(A[i]);
if (!flag) {
set.remove(A[i]);
}
}
Iterator<Integer> iterator = set.iterator();
return iterator.next();
}
解读:使用set集合保存数据,当返回false时表示已经保存过该数值,此时移除数值,最后集合里剩下的那个数值就是不重复的。
更优解
public int singleNumber(int[] A) {
if(A == null || A.length == 0) {
return -1;
}
int res = 0;
for (int i = 0; i < A.length; i++) {
res ^= A[i];
}
return res;
}
解读:异或运算,不同为1,相同为0,任意相同数字返回0(即0000 0000),只有一个单独的数字与0做异或运算,例0000 0101,相同返回0,不同返回1,即返回该数字本身,一次遍历获取结果,时间复杂度O(n)。
2、自己答案
/**
* @param numbers: An array of Integer
* @param target: target = numbers[index1] + numbers[index2]
* @return: [index1, index2] (index1 < index2)
*/
public int[] twoSum(int[] numbers, int target) {
// write your code here
if (numbers == null || numbers.length == 0){
return null;
}
int[] res = new int[2];
Map<Integer,Integer> map = new HashMap<>();
for (int i = 0; i < numbers.length; i++) {
int number = numbers[i];
map.put(i,number);
}
for(Integer index : map.keySet()){
Integer numOne = map.get(index);
for (Integer ind : map.keySet()) {
Integer numTwo = map.get(ind);
if (ind == index){
continue;
}
if (numOne + numTwo == target){
if (ind < index){
res[0] = ind;
res[1] = index;
return res;
}else {
res[0] = index;
res[1] = ind;
return res;
}
}
}
}
return res;
}
解读:遍历,使用map集合保存全部数据,key为索引,value为对应值,再对map集合进行遍历,找到和为指定值时即可返回。
更优解
public int[] twoSum(int[] numbers, int target) {
// write your code here
if (numbers == null || numbers.length == 0){
return null;
}
Map<Integer,Integer> map = new HashMap<>();
for (int i = 0; i < numbers.length; i++) {
int number = numbers[i];
if (map.get(number) != null){ //说明之前存在某个数字与该数字和为目标数值
return new int[]{map.get(number),i}; //前一个数值的index必然小于当前数值的index
}
map.put(target-number,i); //将目标数值与当前数字的差作为key,index作为value
}
int[] res = new int[]{};
return res;
}
解读:由于整数数组中可能会存在负数,因此不能在遍历时将小于目标数值的数字排除,所有数字都要保存。需要保存的有index及数字两个数值作为一组,使用map保存数据,key为目标数值与当前数字的差,value则为数字对应index。例:目标数值是15,当前数字是7,index为1,保存的map的key就是8,需要找到的数字即8,因此在遍历到8的时候就是找到了需要的答案,即7对应的index通过map获取,8的索引即为当前index,放入数组返回即可。时间复杂度为O(n)。
3、自己答案
public class Text {
public static void main(String[] args) {
String str = "asdgjhasbj";
char[] chars = str.toCharArray();
new Text().rotateString(chars,5);
}
/**
* @param str: An array of char
* @param offset: An integer
* @return: nothing
*/
public void rotateString(char[] str, int offset) {
// write your code here
if (str == null || str.length == 0){
return;
}
offset = offset % str.length;
if (offset == 0){
return;
}
int index = str.length - (offset);
int indexB = index;
StringBuffer sbf = new StringBuffer();
for (int i = 0; i < str.length; i++) {
if (i < offset || i < indexB){
sbf.append(str[i]); //保存不需要翻转的全部字符
if (i < offset){
str[i] = str[index];
index++;
}
}else {
break;
}
}
for (int j = 0; j < sbf.length(); j++) {
char c = sbf.toString().charAt(j);
if (offset+j < str.length){
str[offset+j] = c;
}
}
System.out.println(Arrays.toString(str));
}
}
解读:index表示被翻转的字符开始处所在索引,offset表示翻转字符长度,首先将需要翻转的字符进行翻转,放到对应位置,翻转指定长度offset的字符,由于index之前所有字符都要进行翻转,因此将index前的所有字符进行保存,例:str=“abcdefg”,offset为2,index为5,第一次翻转后变为fgcdefg,保存的字符串为abcde。再次遍历保存的字符串,将所有字符按顺序保存到数组中,数组索引从offset处开始,例fgcdefg,保存的字符串为abcde,offset为2,从c处开始保存对应的字符, 即c->a,d->b···最后字符串变为fgabcde。
其它解法:
public void rotateString(char[] str, int offset) {
// write your code here
if (str == null || str.length == 0)
return;
offset = offset % str.length;
reverse(str, 0, str.length - offset - 1);
reverse(str, str.length - offset, str.length - 1);
reverse(str, 0, str.length - 1);
System.out.println(Arrays.toString(str));
}
private void reverse(char[] str, int start, int end) {
for (int i = start, j = end; i < j; i++, j--) {
char temp = str[i];
str[i] = str[j];
str[j] = temp;
}
}
解读:实现了一个从指定位置开始到指定位置结束的翻转方法,先将字符从开始到需要截取字符的开始的索引处进行翻转,再将后半部分进行翻转,最后将整个字符串进行翻转,例:str=“abcdefg”,offset为2,第一次翻转变为edcbafg,第二次翻转变为edcbagf,第三次翻转变为fgabcde。
4、自己答案
public class Text {
public static void main(String[] args) {
List<Integer> list = new Text ().getNarcissisticNumbers(7);
System.out.println(list.toString());
}
/**
* @param n: The number of digits
* @return: All narcissistic numbers with n digits
*/
public List<Integer> getNarcissisticNumbers(int n) {
// write your code here
List<Integer> list = new ArrayList<>();
if (n <= 0){
return new ArrayList<>();
}
int start ;
int end ;
if (n == 1){
start = 0;
end = 9;
}else {
start = new Double(Math.pow(10,n-1)).intValue();
end = new Double(Math.pow(10,n)).intValue()-1;
}
for (int i = start; i <= end; i++) {
int add = 0;
int num = i;
while (num != 0){ //n为0时说明所有位上的数字已经计算完
add += Math.pow(num % 10,n); //对每位上的数字进行n次方求和
if (add > i){ //和已经大于当前数字,不需要继续计算,直接返回
break;
}
num = num / 10;
}
if (add == i){ //水仙花数
list.add(i);
}
}
return list;
}
}
解读:首先根据输入的n找到需要判断的数值区间,Math.pow(x,y),此方法得到x的y次方,然后对每个数字进行各个位上的n次方的求和,如果是水仙花则保存返回。
其他解法:暂无。
5、自己答案
使用多个if
public static void main(String[] args) {
List<String> list = new Text().fizzBuzz(35);
System.out.println(list.toString());
}
/**
* @param n: An integer
* @return: A list of strings.
*/
public List<String> fizzBuzz(int n) {
List<String> list = new ArrayList<>();
// write your code here
for (int i = 1; i <= n; i++) {
if (i % 15 == 0){ //既能被3整除又能被5整除
list.add("fizz buzz");
}else if (i % 3 == 0){ //被3整除
list.add("fizz");
}else if (i % 5 == 0){ //被5整除
list.add("buzz");
}else {
list.add(i+"");
}
}
return list;
}
只使用一个if
public List<String> fizzBuzz(int n) {
List<String> list = new ArrayList<>();
int i = 1;
while (i <= n){
while (i <= n && i % 3 != 0 && i % 5 != 0){ //既不能被3整除又不能被5整除
list.add(i + "");
i++;
}
if (i <= n && i % 3 == 0 && i % 5 == 0){ //既能被3整除又能被5整除
i++;
list.add("fizz buzz");
continue;
}
while (i <= n && i % 3 == 0){ //被3整除
i++;
list.add("fizz");
}
while (i <= n && i % 5 == 0){ //被5整除
i++;
list.add("buzz");
}
}
return list;
}
解读:使用while来代替if判断,取巧。
6、答案
public static void main(String[] args) {
int sum = new Text().aplusb(4,71);
System.out.println(sum);
}
/**
* @param a: An integer
* @param b: An integer
* @return: The sum of a and b
*/
public int aplusb(int a, int b) {
if (b == 0){
return a;
}
//1、各位相加 不进位 0+0 0 0+1 1 1+0 1 1+1 0 相同为0 不同为1 异或运算
int numA = a^b;
//2、进位 0+0 0+1 1+0 不进位 1+1 进位 相当于先做位与运算保留1+1的位 再做向左移位 0 0 0 1 << 00 00 00 10
int numB = (a & b) << 1;
//3、前两步得到的结果相加,调用自身方法
return aplusb(numA,numB);
}
解读:使用位运算符来计算。
计算加法时可以分三步,例如15+16
第一步,各位相加。10+10=20,5+6=11,如果不进位时,第一步结果是20+1=21
第二步,进位。10+10=20,不需要进位,5+6=11,需要进位,得到进位结果10
第三部,将前两步的和相加。21+10=31,得到结果
如果是需要再进位的,此时需要再次分三步一步步走,即运算不是一步计算到位,需要递归调用,例:89+98
1、80+90=170,9+8=17,70+7=77
2、80+90=170,进位,9+8=17,进位,得到100+10=110
3、77+110 即 1、100+0=100,70+10=80 7+0=7 得到187,2、无操作,3、得到结果为187
同理对于位运算也可以分三步:
第一步,各位相加,不进位。0+0=0,0+1=1,1+0=1,1+1=0,相当于相同位结果是0,不同则为1,即异或运算,因此第一步使用异或运算得到一个结果。
第二步,进位。0+0 0+1 1+0都不进位,1+1进位,相当于做位与运算得到结果再左移一位,即0+0=0 0+1=0 1+0=0 1+1=1 左移后变为00 00 00 10 即1+1进位,其余不进位。
第三步,前两步和相加,即递归调用自身即可。
7、自己答案
public static void main(String[] args) {
System.out.println(new Text().getSum(1,50));
}
/**
* @param A: The A
* @param B: The B
* @return: Returns the sum of all qualified numbers
*/
public int getSum(int A, int B) {
// Write your code here
if (A > B || A < 0 || B < 0){
return 0;
}
int sum = 0;
for (int i = A; i <= B; i++) {
if (i % 3 == 0){
sum += i;
}
}
return sum;
}
解读:遍历从A到B的所有数字,找到所有被3整除的数字加一起返回
/**
* @param A: The A
* @param B: The B
* @return: Returns the sum of all qualified numbers
*/
public int getSum(int A, int B) {
// Write your code here
if (A > B || A < 0 || B < 0){
return 0;
}
int sum = 0;
if (A % 3==0){
while (A <= B){
sum += A;
A += 3;
}
}else if (A % 3 == 1){
A += 2;
while (A <= B){
sum += A;
A += 3;
}
}else {
A += 1;
while (A <= B){
sum += A;
A += 3;
}
}
return sum;
}
解读:判断A是否被3整除,然后一直找到B,中间只取被3整除的数字相加,循环次数要少于上面方法。
8、自己答案
public static void main(String[] args) {
System.out.println(new Text().isUnique("asdgh"));
}
/*
* @param str: A string
* @return: a boolean
*/
public boolean isUnique(String str) {
// write your code here
Set<String> set = new HashSet<>();
char[] chars = str.toCharArray();
for (int i = 0; i < chars.length; i++) {
boolean flag = set.add(chars[i] + ""); //存在相同字符
if (!flag){
return false;
}
}
return true;
}
解读:使用set集合保存每个字符,利用其不可保存相同对象特性,当放入一个对象返回false时即找到了相同字符
其他答案
/*
* @param str: A string
* @return: a boolean
*/
public boolean isUnique(String str) {
// write your code here
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (str.indexOf(c) != str.lastIndexOf(c)){ //判断首个出现字符的索引和最后出现字符的索引是否相同,不同则重复
return false;
}
}
return true;
}
解读:判断字符串中该字符出现的索引,如果只有一个该字符,则从前从后找到的索引应该一致,不一致时说明存在相同字符
/*
* @param str: A string
* @return: a boolean
*/
public boolean isUnique(String str) {
// write your code here
boolean[] arr = new boolean[256];
for (int i = 0; i < str.length(); i++) {
int c = str.charAt(i);
if (arr[c]){ //存在相同字符
return false;
}
arr[c] = true; //将该字符对应数组值为true
}
return true;
}
解读:因为ASCII字符只有256个,所以开辟一个256长度的数组,默认值全为false,遍历字符时判断数组该下标对应值是否为true,不为true将数组对应值改为true,表示出现过,为true说明说明已经出现过,此时重复出现
9、自己答案
public static void main(String[] args) {
System.out.println(new Text().reverseWords("hello world"));
System.out.println(new Text().reverseWords("the sky is blue"));
System.out.println(new Text().reverseWords(" the sky is blue "));
System.out.println(new Text().reverseWords("the sky is blue "));
System.out.println(new Text().reverseWords(" the sky is blue "));
System.out.println(new Text().reverseWords(" the sky is blue "));
}
/*
* @param s: A string
* @return: A string
*/
public String reverseWords(String s) {
// write your code here
String[] split = s.split(" );
StringBuilder sbf = new StringBuilder();
for (int i = split.length-1; i >= 0; i--) {
if ("".equals(split[i])){
continue;
}
sbf.append(split[i]).append(" ");
}
return sbf.toString();
}
解读:按空字符串分割,如果是多个空字符串连在一起的,遍历数组时将空字符串时不要即可。
10、自己答案
public static void main(String[] args) {
System.out.println(new Text().firstUniqChar("abaccdeff"));
}
/**
* @param str: str: the given string
* @return: char: the first unique character in a given string
*/
public char firstUniqChar(String str) {
// Write your code here
if (str == null || "".equals(str)){
return ' ';
}
char[] chars = str.toCharArray();
for (int i = 0; i < chars.length; i++) {
if (str.indexOf(chars[i]) == str.lastIndexOf(chars[i])){
return chars[i];
}
}
return ' ';
}
解读:挨个字符判断从头数和从后数的索引是否一致,不一致说明存在多个一样字符,一致说明唯一
11、自己答案
public static void main(String[] args) {
System.out.println(new Text().isLegalIdentifier("abaccdeff"));
System.out.println(new Text().isLegalIdentifier(""));
System.out.println(new Text().isLegalIdentifier("123_1das"));
System.out.println(new Text().isLegalIdentifier("a123_"));
System.out.println(new Text().isLegalIdentifier("_123"));
System.out.println(new Text().isLegalIdentifier("a_123"));
}
/**
* @param str: The identifier need to be judged.
* @return: Return if str is a legal identifier.
*/
public boolean isLegalIdentifier(String str) {
// Write your code here.
if (str == null || "".equals(str)){
return true;
}
String regex = "[a-zA-Z_]+[0-9a-zA-Z_]*";
if (str.matches(regex)){
return true;
}else {
return false;
}
}
解读:使用正则表达式判断
12、自己答案
public static void main(String[] args) {
System.out.println(new Solution().deduplication(new int[]{2,5,8,2,4,1,6,5,2}));
System.out.println(new Solution().deduplication(new int[]{1,3,1,4,4,2}));
}
/**
* @param nums: an array of integers
* @return: the number of unique integers
*/
public int deduplication(int[] nums) {
// write your code here
int index = nums.length-1;
Set<Integer> set = new HashSet<>();
for (int i = 0; i <= index; i++) {
int numA = nums[i];
boolean flag = set.add(numA); //判断是否重复
if (!flag){
nums[i] = nums[index];
nums[index--] = numA;
i--;
}
}
return index+1;
}
解读:利用set集合保存元素唯一特性,重复元素向后放
13、自己答案
class Interval {
int start, end;
public Interval(int start, int end) {
this.start = start;
this.end = end;
}
}
public static void main(String[] args) {
List<Interval> list = new ArrayList<>();
Interval interval = new Interval(465,497);
list.add(interval);
interval = new Interval(386,462);
list.add(interval);
interval = new Interval(354,380);
list.add(interval);
interval = new Interval(134,189);
list.add(interval);
interval = new Interval(199,282);
list.add(interval);
interval = new Interval(18,104);
list.add(interval);
interval = new Interval(499,562);
list.add(interval);
interval = new Interval(4,14);
list.add(interval);
interval = new Interval(111,129);
list.add(interval);
interval = new Interval(292,345);
list.add(interval);
System.out.println(new Solution().canAttendMeetings(list));
}
/**
* @param intervals: an array of meeting time intervals
* @return: if a person could attend all meetings
*/
public boolean canAttendMeetings(List<Interval> intervals) {
// Write your code here
for (int i = 0; i < intervals.size(); i++) {
Interval intervalA = intervals.get(i);
for (int j = i+1; j < intervals.size(); j++) {
Interval intervalB = intervals.get(j);
if (intervalA.start < intervalB.end && intervalA.end > intervalB.start){
return false;
}
}
}
return true;
}
解读:逐个比较,时间交集条件是,一个的开始时间小于另一个的结束时间,并且结束时间大于另一个的开始时间
更优解:
public boolean canAttendMeetings(List<Interval> intervals) {
// Write your code here
if(intervals == null || intervals.size() == 0) return true;
Collections.sort(intervals, new Comparator<Interval>() {
@Override
public int compare(Interval o1, Interval o2) {
return o1.start - o2.start;
}
});
int end = intervals.get(0).end;
for(int i = 1; i < intervals.size(); i++){
if(intervals.get(i).start < end) {
return false;
}
end = Math.max(end, intervals.get(i).end);
}
return true;
}
解读:先对集合按照开始时间从小到大进行排序,然后遍历比较结束时间与开始时间,当某个时间段前的结束时间大于该时间段的开始时间,说明存在交集。
14.自己答案
public static void main(String[] args) {
System.out.println(new Solution().searchInsert(new int[]{1,3,5,6},5));
System.out.println(new Solution().searchInsert(new int[]{1,3,5,6},2));
System.out.println(new Solution().searchInsert(new int[]{1,3,5,6},7));
System.out.println(new Solution().searchInsert(new int[]{1,3,5,6},0));
}
/**
* @param A: an integer sorted array
* @param target: an integer to be inserted
* @return: An integer
*/
public int searchInsert(int[] A, int target) {
// write your code here
int index = 0;
for (int i = 0; i < A.length; i++) {
int num = A[i];
int pre;
if (num == target){
index = i;
break;
}
if (i != 0){
pre = A[i - 1];
if (pre < target){
if (num > target){
index = i;
break;
}else {
if (i == A.length - 1){
index = A.length;
}
}
}
}
}
return index;
}
解读:遍历,找到对应目标数字,同时判断上一个数字和当前数字与目标数字比较,当上一个数字比目标数字小,当前数字比目标数字大时返回当前数字索引,当所有数字比目标数字小时返回数组长度,当所有数字比目标数字大时返回0
更优解
public int searchInsert(int[] A, int target) {
// write your code here
if (A == null || A.length == 0){
return 0;
}
int start = 0;
int end = A.length - 1;
while (start <= end){
int mid = (start + end) / 2;
if (A[mid] == target){
return mid;
}else if (A[mid] > target){
end = mid - 1;
}else {
start = mid + 1;
}
}
return end+1;
}
解读:使用二分查找法,每次排除一半数据,找到目标数字时返回当前索引,未找到时返回后一个数字索引+1
15、自己答案
/**
* @param array: the input array
* @return: the sorted array
*/
public int[][] multiSort(int[][] array) {
// Write your code here
for (int i = 0; i < array.length; i++) {
for (int j = i+1; j < array.length; j++) {
if (array[i][1] < array[j][1]){
int[] tmp = array[j];
array[j] = array[i];
array[i] = tmp;
}else if (array[i][1] == array[j][1] && array[i][0] > array[j][0]){
int[] tmp = array[j];
array[j] = array[i];
array[i] = tmp;
}
}
}
return array;
}
解读:对数组排序两两比较排序,分值大的在前, 分值相同的学号小的在前
更优解:
public int[][] multiSort1(int[][] array) {
// Write your code here
for (int i = 0; i < array.length; i++) {
for (int j = i + 1; j < array.length; j++) {
if (!cmp(array[i], array[j])) {
int tmp = array[i][0];
array[i][0] = array[j][0];
array[j][0] = tmp;
tmp = array[i][1];
array[i][1] = array[j][1];
array[j][1] = tmp;
}
}
}
return array;
}
boolean cmp(int[] a, int[] b) {
if (a[1] > b[1]) {
return true;
}
if (a[1] == b[1] && a[0] < b[0]) {
return true;
}
return false;
}
解读:两两比较,不交换地址,只交换数组里数据
16、冒泡排序
/**
* @param A: an integer array
* @return: nothing
*/
public void sortIntegers(int[] A) {
// write your code here
if (A==null || A.length == 0){
return;
}
for (int i = 0; i < A.length; i++) {
for (int j = i+1; j < A.length; j++) {
if (A[i] > A[j]){
int temp = A[i];
A[i] = A[j];
A[j]= temp;
}
}
}
}
快速排序
public void quickSort(int[] A,int start,int end){
if (A==null || A.length == 0){
return;
}
int temp = A[start];
if (start >= end){
return;
}
int index = end;
for (int k = start; k <= index; k++) {
if (A[k] >= temp) {
int num = A[k];
A[k] = A[index];
A[index] = num;
index--;
if (A[k] != temp){
k--;
}
}
}
quickSort(A,start,index);
quickSort(A,index+1,end);
}
另一种快速排序
public void quickSort1(int[] arr, int low, int high){
if(arr.length <= 0) return;
if(low >= high) return;
int left = low;
int right = high;
int temp = arr[left]; //挖坑1:保存基准的值
while (left < right){
while(left < right && arr[right] >= temp){ //坑2:从后向前找到比基准小的元素,插入到基准位置坑1中
right--;
}
arr[left] = arr[right];
while(left < right && arr[left] <= temp){ //坑3:从前往后找到比基准大的元素,放到刚才挖的坑2中
left++;
}
arr[right] = arr[left];
}
arr[left] = temp; //基准值填补到坑3中,准备分治递归快排
System.out.println("Sorting: " + Arrays.toString(arr));
quickSort1(arr, low, left-1);
quickSort1(arr, left+1, high);
}
解读:冒泡排序:两两比较,较小的前移,复杂度O(n²)
快速排序:选择一个数作为基准,将比基准小的数放到基准数前,比基准大的放在后面,相等的放在哪边都行,然后分成两段再分别进行递归调用,复杂度O(nlogn)
17、答案
/**
* @param m: the limit
* @param k: the sum of choose
* @param arr: the array
* @return: yes or no
*/
public String depress(int m, int k, int[] arr) {
// Write your code here.
if (arr == null ||arr.length == 0){
return "yes";
}
int[] res = new int[k];
int index = 0;
int sum = 0;
for (int i = 0; i < arr.length; i++) {
if (index == k){
Arrays.sort(res);
if (arr[i] < res[index-1]){
sum = sum - res[index-1] + arr[i];
res[index-1] = arr[i];
if (sum < m){
return "yes";
}
}
}
if (index < k){
res[index] = arr[i];
index++;
sum += arr[i];
}
}
return "no";
}
解读:开辟一个k长的数组,作为最小堆,保存数组中遍历到的最小元素,发现这些数值的和小于目标数m,即返回yes,未找到则返回no
public String depress(int m, int k, int[] arr) {
// Write your code here.
if (arr == null ||arr.length == 0){
return "yes";
}
Arrays.sort(arr);
int sum = 0;
for (int i = 0; i < arr.length; i++) {
if (i < k){
sum += arr[i];
}
}
if(sum < m){
return "yes";
}else {
return "no";
}
}
解读:对整个数组进行排序,找到前k个数值和,与m进行判断
18、答案:
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}
/**
* @param head: the given linked list
* @return: the array that store the values in reverse order
*/
public List<Integer> reverseStore(ListNode head) {
// write your code here
if (head == null){
return null;
}
List<Integer> list = new ArrayList<>();
while (head != null){
list.add(head.val);
head = head.next;
}
Collections.reverse(list);
return list;
}
其它解
List<Integer> list = new ArrayList<>();
public List<Integer> reverseStore(ListNode head) {
// write your code here
if (head == null){
return null;
}
reverseStore(head.next);
list.add(head.val);
return list;
}
解答:倒序放数据,想到递归方法,每次将下一个节点进行递归判断,存在则保存数值即可。
19、自己答案
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}
/**
* @param head: the head of linked list.
* @return: a middle node of the linked list
*/
public ListNode middleNode(ListNode head) {
// write your code here
if (head == null){
return null;
}
if (head.next == null){
return head;
}
List<ListNode> list = new ArrayList<>();
int index = -1;
while (head != null){
list.add(head);
head = head.next;
index++;
}
return list.get(index/2);
}
解读:遍历找到全部数据,取中间索引对应数据
20、自己答案
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}
/**
* @param head: The head of linked list.
* @param val: An integer.
* @return: The head of new linked list.
*/
public ListNode insertNode(ListNode head, int val) {
// write your code here
ListNode listNode = new ListNode(val);
ListNode res = head;
if (head == null){
return listNode;
}else {
while (head != null){
ListNode cur = head;
int curVal = head.val;
if (curVal > val){ //当前值大于给定值时,向前插入,只有头结点才有此情况
res = listNode;
listNode.next = head;
break;
}else {
head = head.next;
if (head != null){ //下个节点不为null,进行当前值,下个结点值和给定值比较
int nextVal = head.val;
if (curVal <= val && nextVal >= val){
cur.next = listNode;
listNode.next = head;
break;
}
}else { //下个节点值为null
cur.next = listNode;
break;
}
}
}
}
return res;
}
解读:判断头节点值是否大于给定值,小于则改变头节点,大于则向下进行判断,当给定值大于最后一个节点值时,尾节点为给定值,介于两个节点之间时向中间插入替换
其他答案:
public ListNode insertNode(ListNode head, int val) {
// write your code here
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode p = dummy;
while(p != null){
ListNode next = p.next;
if(next != null && next.val < val){
p = p.next;
}else{ //当p.val<val && next.val>val时代表找到插入节点的位置
ListNode newNode = new ListNode(val);
newNode.next = next;
p.next = newNode;
break;
}
}
return dummy.next;
}
21、自己答案
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}
/**
* @param head: the first node of linked list.
* @return: An integer
*/
public int countNodes(ListNode head) {
// write your code here
if (head == null){
return 0;
}
int res = 0;
while (head != null){
head = head.next;
res++;
}
return res;
}
解读:遍历所有节点,找到节点数量
22、自己答案
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}
/**
* @param head: The first node of linked list
* @param n: the start index
* @param m: the end node
* @return: A ListNode
*/
public ListNode deleteNode(ListNode head, int n, int m) {
// Write your code here
if (head == null || n > m){
return null;
}
int index = 0;
ListNode pre = null;
ListNode res = head;
while (head != null){
if (n == 0){
if (index == m){
return head.next;
}
}
if (index == n-1){
pre = head;
}
if (index == m){
pre.next = head.next;
return res;
}
head = head.next;
index++;
}
return res;
}
解答:判断n为0,则找到m处值即可直接返回,n不为0,使用中间变量保存n节点前的值,当找到第m个节点时修改中间变量的next节点,然后返回原头节点即可
23、答案
class TreeNode {
public int val;
public TreeNode left, right;
public TreeNode(int val) {
this.val = val;
this.left = this.right = null;
}
}
/**
* @param root: The root of binary tree.
* @return: An integer
*/
public int maxDepth(TreeNode root) {
// write your code here
if (root == null){
return 0;
}
int left = maxDepth(root.left);
int right = maxDepth(root.right);
return Math.max(left, right) + 1;
}
解读:从根节点分别向左右叶子节点找到最深处
24、答案
class TreeNode {
public int val;
public TreeNode left, right;
public TreeNode(int val) {
this.val = val;
this.left = this.right = null;
}
}
/**
* @param root: A Tree
* @return: Inorder in ArrayList which contains node values.
*/
public List<Integer> inorderTraversal(TreeNode root) {
// write your code here
Stack<TreeNode> stack = new Stack<TreeNode>();
ArrayList<Integer> result = new ArrayList<Integer>();
TreeNode cur = root;
while (cur != null || !stack.isEmpty()){
while (cur != null){
stack.push(cur);
cur = cur.left;
}
cur = stack.pop();
result.add(cur.val);
cur = cur.right;
}
return result;
}
解读:中序遍历:从根节点向下找子节点,从左找起,即最左的是第一个元素,然后从该节点向上找到其根节点,再找该根节点的右节点的最下的左节点,然后再依次向上找,最后返回遍历结果。
使用栈保存每一个根结点,当当前的节点的左节点不为空时,将当前节点入栈保存,当前节点指向左节点,直到当前节点为空,说明找到最左节点,将该值保存到集合中,然后从栈中获取根节点,当前节点指向根节点的右节点,存在则继续找该节点的左节点,不存在则以根节点作为该根的根节点的左节点进行循环遍历,直到找到所有节点为止。
25、答案
class TreeNode {
public int val;
public TreeNode left, right;
public TreeNode(int val) {
this.val = val;
this.left = this.right = null;
}
}
/**
* @param root: the root of the binary tree
* @return: all root-to-leaf paths
*/
public List<String> binaryTreePaths(TreeNode root) {
// write your code here
List<String> paths = new ArrayList<>();
if (root == null) {
return paths;
}
List<String> leftPaths = binaryTreePaths(root.left);
List<String> rightPaths = binaryTreePaths(root.right);
for (String path : leftPaths) {
paths.add(root.val + "->" + path);
}
for (String path : rightPaths) {
paths.add(root.val + "->" + path);
}
// root is a leaf
if (paths.size() == 0) {
paths.add("" + root.val);
}
return paths;
}
解读:使用分治算法
26、答案
class TreeNode {
public int val;
public TreeNode left, right;
public TreeNode(int val) {
this.val = val;
this.left = this.right = null;
}
}
/**
* @param root: the root of the binary tree
* @return: the number of nodes
*/
public int getAns(TreeNode root) {
// Write your code here
if (root == null){
return 0;
}
int left = getAns(root.left);
int right = getAns(root.right);
return left+right+1;
}
解读:递归找到所有节点
27、答案
/**
* @param a: the n numbers
* @param k: the number of integers you can choose
* @return: how many ways that the sum of the k integers is a prime number
*/
public int getWays(int[] a, int k) {
// Write your code here
if (a == null || a.length == 0 || k == 0){
return 0;
}
return dfs(0, 0, k,a,0);
}
/**
* 递归判断k个数为素数的总可能数
* @param sum 综合
* @param p 数组当前遍历到的索引
* @param k 要求的k个数
* @param a 数组
* @param count 已经找到的素数个数
* @return 总素数个数
*/
public int dfs(int sum,int p,int k,int[] a,int count){
if(k==0){
if(isPrime(sum)){
count += 1;
}else {
count += 0;
}
}else {
for(int i=p;i<=a.length-k;i++){ //当前所选下标的最大值,若超过,则会选不够;因为这是按照从前往后的顺序以此进行选择
count = dfs(sum+a[i],i+1,k-1,a,count); //每递归一次,就会选出一个数来,k就减1
}
}
return count;
}
/**
* 判断是否为素数
* @param num 数字
* @return 素数返回true 否则返回false
*/
public boolean isPrime(int num){
if (num == 1){
return false;
}
for (int i = 2; i < num; i++) {
if (num % i == 0){
return false;
}
}
return true;
}
解读:从第一个数开始找,第一个数不变,后面找到k-1个数进行组合,找完后再将第二个数作为基准进行查找,知道找遍所有的可能。
28、答案
/**
* @param nums: Give an array numbers of n integer
* @return: Find all unique triplets in the array which gives the sum of zero.
*/
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> results = new ArrayList<>();
if (nums == null || nums.length < 3) {
return results;
}
Arrays.sort(nums);
for (int i = 0; i < nums.length - 2; i++) {
// skip duplicate triples with the same first numebr
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
int left = i + 1, right = nums.length - 1;
int target = -nums[i];
twoSum(nums, left, right, target, results);
}
return results;
}
public void twoSum(int[] nums,
int left,
int right,
int target,
List<List<Integer>> results) {
while (left < right) {
if (nums[left] + nums[right] == target) {
ArrayList<Integer> triple = new ArrayList<>();
triple.add(-target);
triple.add(nums[left]);
triple.add(nums[right]);
results.add(triple);
left++;
right--;
// skip duplicate pairs with the same left
while (left < right && nums[left] == nums[left - 1]) {
left++;
}
// skip duplicate pairs with the same right
while (left < right && nums[right] == nums[right + 1]) {
right--;
}
} else if (nums[left] + nums[right] < target) {
left++;
} else {
right--;
}
}
}
29、答案
public class Node {
int val;
Node next;
Node(int x) {
val = x;
next = null;
}
}
/**
* 遍历
*/
public static Node reverseList(Node node){
if (node == null){
return null;
}
Node pre = null; //保存上一个节点
Node next = null; //下一个节点
while (node != null){ //a->b->c
next = node.next; //获取下一个节点 1、b 2、c
node.next = pre; //当前节点的下一个节点指向上一个节点,实现反转 1、a->null 2、b->a
pre = node; //上一个节点指向当前节点 1、a 2、b
node = next; //当前节点指向下一个节点 1、b 2、c
}
return pre;
}
/**
* 递归
*/
public static Node reverseList1(Node node) {
if (node == null || node.next == null){
return node;
}
Node temp = node.next; //下一个节点
Node next = reverseList1(temp); //从后向前获取节点
temp.next = node; //下一个节点的下一个节点指向当前节点 即 a->b 变为 b->a->b head为a,即当前节点 temp为b节点 要反转,所以b节点的下一个节点指向a节点
node.next = null; //断开当前节点对下个节点的引用 即 b->a->b 变为b->a
return next;
}
30、答案
public static Node searchNode(Node head){
if (head == null){
return null;
}
Node pHead = head; //一次走一步
Node nHead = head; //一次走两步
while (nHead != null && nHead.next != null && nHead.next.next != null){ //后面够走两步
nHead = nHead.next.next;
pHead = pHead.next;
}
return pHead; //奇数则返回正中间结点,偶数则返回中间两个结点中前一个结点
}
解读:两个指针一起走,一个一次走两个结点,一个一次走一个结点,当走的快的指针到达尾部时,慢的指针刚好到达中间,偶数个结点时返回中间两个结点中前一个结点
31、答案
public static boolean IsLoop(Node head){
if (head == null){
return false;
}
Node pHead = head; //一次走一步
Node nHead = head; //一次走两步
while (nHead != null && nHead.next != null){
pHead = pHead.next;
nHead = nHead.next.next;
if (pHead == nHead){
return true;
}
}
return false;
}
解读:一个快指针一次走两步,一个满指针一次走一步,若存在环,则两个指针一定会相遇,如果不存在环,快指针会先到达尾部指向null,每次循环时两个指针进行比较,直到相等(存在环)或者快指针指向null(不存在环)
32、答案
public static Node deleteElem(Node head,int k){
if (head == null || k < 1){
return null;
}
Node pHead = head; //一次走一步
Node nHead = head; //先走k步
Node pre = null; //保存上一个结点
for (int i = 1; i < k && nHead != null; i++) {
nHead = nHead.next;
if (nHead == null){
System.out.println("k不合法");
return null;
}
}
while (nHead.next != null){
nHead = nHead.next;
pre = pHead;
pHead = pHead.next;
}
if (pre == null){
head = head.next;
}else {
pre.next = pHead.next;
}
return head;
}
解读:一个指针先走k步,然后两个指针一起走,直到先走的指针走到最后,走的慢的指针当前结点就是倒数第k个结点,一个指针保存当前结点的上一个结点,如果被删除的结点刚好是头结点, 则将头结点的下一个结点作为新的头结点,否则进行结点删除
33、答案
public static Node mergeTwoLists(Node head,Node head1){
if (head == null || head1 == null){
return head == null ? head1 : head;
}
Node node = null;
Node res = null; //返回结果头结点
Node p = head;
Node q = head1;
while (p != null || q != null){
if (p != null && q != null){
if (p.val <= q.val){
if (node == null){
node = p;
res = node;
}else {
node.next = p;
node = node.next;
}
p = p.next;
}else {
if (node == null){
node = q;
res = node;
}else {
node.next = q;
node = node.next;
}
q = q.next;
}
}else {
if (p == null && q != null){
node.next = q;
q = q.next;
}
if (q == null && p != null){
node.next = p;
p = p.next;
}
}
}
return res;
}
解读:同时遍历两个链表,将新链表指向值小的那个结点
其它答案:
public static Node mergeTwoLists(Node node1, Node node2) {
if(node1==null) return node2;
if(node2==null) return node1;
Node temp;
if(node1.val<node2.val){
temp = node1;
temp.next = mergeTwoLists(node1.next,node2);
}else{
temp = node2;
temp.next = mergeTwoLists(node1,node2.next);
}
return temp;
}
解读:递归实现