目录
1. 题目:两数之和
题目:给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。你可以按任意顺序返回答案。
代码:
import java.util.HashMap;
public class TwoSum {
//暴力法
public static int[] twoSum(int[] array, int target){
int[] result = new int[2];
for(int i=0; i<array.length; i++){
for(int j=i+1; j<array.length; j++){
if(array[i] + array[j] == target){
result[0] = i;
result[1] = j;
return result;
}
}
}
return result;
}
//哈希表法
public static int[] twoSum2(int[] array, int target){
HashMap<Integer, Integer> hashMap = new HashMap<Integer, Integer>();
int[] result = new int[2];
int rest = 0;
for(int i=0; i<array.length; i++){
hashMap.put(array[i], i);
}
for(int i=0; i<array.length; i++){
rest = target - array[i];
if(hashMap.containsKey(rest) && hashMap.get(rest) != i){
result[0] = i;
result[1] = hashMap.get(rest);
return result;
}
}
return result;
}
public static void main(String[] args) {
int[] array = {21,5,4,1,8,3};
int target = 7;
int[] result = twoSum2(array, target);
System.out.println("满足条件的数组下标为:" + result[0]+", "+result[1]);
}
}
2. 题目:两数相加(链表)
题目:给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
分析:
该题是经典的两数相加问题,数字以逆序存储在链表中,也就是链表的第一位就是数字的个位,所以可以直接按照链表顺序依次进行相加,
一个需要注意的点就是,每次相加时,需要同时加上进位carry,然后如果此次相加结果大于10,则取个位数字,并将进位保留到下一次链表相加。
简单来讲,每个链表结点相加规则如下:
数值:(l1.val + l2.val + carry) % 10
进位:(l1.val + l2.val + carry) / 10
/** 新建一个ListNode类,然后调用
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
代码:
import java.util.List;
public class AddTwoNumbers {
//常规解法
public static ListNode addTwoNumbers(ListNode l1, ListNode l2){
ListNode head = null;
ListNode tail = null;
int carry = 0;
while(l1 != null || l2 != null){
int listNode1 = 0;
if(l1 != null){
listNode1 = l1.val;
l1 = l1.next;
}
int listNode2 = 0;
if(l2 != null){
listNode2 = l2.val;
l2 = l2.next;
}
int sum = listNode1 + listNode2 + carry;
if(head == null){
head = tail = new ListNode(sum%10);
}else {
tail.next = new ListNode(sum%10);
tail = tail.next;
}
carry = sum / 10;
}
if( carry > 0){
tail.next = new ListNode(carry);
}
return head;
}
//递归解法
public static ListNode addTwoNumbers2(ListNode l1, ListNode l2, int carry){
if(l1 == null && l2 == null && carry == 0){
return null;
}
int nextNode1 = 0;
int nextNode2 = 0;
if(l1 != null){
nextNode1 = l1.val;
l1 = l1.next;
}
if(l2 != null){
nextNode2 = l2.val;
l2 = l2.next;
}
int sum = nextNode1 + nextNode2 + carry;
ListNode result = new ListNode(sum % 10);
result.next = addTwoNumbers2(l1, l2, carry); //递归
return result;
}
//主函数
public static void main(String[] args) {
ListNode l1 = new ListNode(0); //创建首节点
ListNode nextNode1; //创建下一个节点
nextNode1 = l1; //初始化下一个节点,让其指向首节点
for(int i=1; i<3; i++){
ListNode newNode = new ListNode(i); //创建新的结点
nextNode1.next = newNode; //连结新节点
nextNode1 = nextNode1.next; //节点后移
}
ListNode l2 = new ListNode(0);
ListNode nextNode2;
nextNode2 = l2;
for(int j=5; j>2; j--){
ListNode newNode = new ListNode(j);
nextNode2.next = newNode;
nextNode2 = nextNode2.next;
}
ListNode result = addTwoNumbers2(l1, l2, 0);
result = result.next;
while(result != null){
System.out.print(result.val + " ");
result = result.next;
}
}
}
3. 题目:无重复字符的最长字串
题目:给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
思路:
HashSet不能存储重复元素;
HashSet不确保插入顺序;
HashSet是非线程安全的。
把出现过的字符都放入 set 中,遇到 set 中没有的字符就加入 set 中并更新结果 res,然后右边界 +1。如果遇到重复的,则删除 set 中下标为左边界的字符,即遇到一个重复字符,则删除一个 set 中的字符,然后左边界 +1:
代码:
import java.util.HashSet;
public class LengthOfLongestSubstring {
public static int lengthOfLongestSubstring(String str){
int left = 0;
int right = 0;
int length = 0;
HashSet<Character> hashSet = new HashSet<Character>();
while (right < str.length()){
if(!hashSet.contains(str.charAt(right))){
hashSet.add(str.charAt(right));
right++;
length = Math.max(length, hashSet.size()); //始终保存出现过的最长的(没有重复字符的)子字符串
} else {
hashSet.remove(str.charAt(left)); //如果重复的不是最左边的字符,这个移除之后,进入下一轮循环,hashSet中依然含有重复的字符,会再一次走这条路,移除,直至移除掉重复的字符
left++;
}
}
return length;
}
public static void main(String[] args) {
String str = "abcdbc";
System.out.println("最长字串的长度为:"+lengthOfLongestSubstring(str));
}
}
4. 题目:寻找两个正序数组的中位数
题目:给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。
请你找出并返回这两个正序数组的 中位数 。
代码:
public class FindMedianSortedArrays {
public static double findMedianSortedArrays(int[] num1, int[] num2){
int l1 = num1.length;
int l2 = num2.length;
int length = l1 + l2;
int[] combineArray = new int[length];
int i=0, j=0, k=0;
while(i<l1 && j<l2){
if(num1[i] < num2[j]){
combineArray[k++] = num1[i++];
}else {
combineArray[k++] = num2[j++];
}
}
while (i<l1){
combineArray[k++] = num1[i++];
}
while (j<l2){
combineArray[k++] = num2[j++];
}
if(length % 2 == 0){
return (combineArray[length/2 -1] + combineArray[length/2])/2.0;
}else {
return combineArray[length/2];
}
}
public static void main(String[] args) {
int[] num1 = {1,2};
int[] num2 = {3,4};
double result = findMedianSortedArrays(num1, num2);
System.out.println("两个正序数组的中位数为: " + result);
}
}
5. 题目:最长回文子串
题目:给你一个字符串 s,找到 s 中最长的回文子串。 示例 1: 输入:s = "babad" 输出:"bab" 解释:"aba" 同样是符合题意的答案。
思路:
回文字符串:是一个正读和反读都一样的字符串。回文中心的两侧互为镜像。 假定从字符串的每个字符开始,都有回文数,遍历整体字符串的长度,算出每个字符回文数的长度,最后比较输出最长 如果假设每个字符都存在回文数,那考虑这个字符奇数回文数的情况和偶数个回文数的情况
代码:
public class LongestPalindrome {
public static void main(String[] args) {
String str = "abefeba";
String palindrome = longestPalindrome(str);
System.out.println(palindrome);
}
public static String longestPalindrome(String s){
String result = ""; //用以保存最长回文子串
if(s.length() < 2){ //如果整个字符串长度小于2,则直接返回
return s;
}
for(int i=0; i<s.length(); i++){ //假定从字符串的每个字符开始,都有回文数,遍历整体字符串的长度
result = findPalindrome(s, i, i, result); //当前字符的回文串是奇数的情况
result = findPalindrome(s, i, i+1, result); //当前字符的回文串是偶数的情况
}
return result;
}
public static String findPalindrome(String s, int before, int after, String result){
while(before>=0 && after<s.length() && (s.charAt(before) == s.charAt(after))){ //满足回文条件,则往左右扩展
before--;
after++;
}
//上面退出while的时候,before多减了1,after多加了1。所以要先复原最后满足回文的before和after值。
if(((after-1)-(before+1)+1) > result.length()){
result = s.substring(before+1, after); //如果新的回文子串更长,则替换result。subString(i,j) 截取子字符串,包含起始索引,不包含结束索引
}
return result;
}
}
6. 题目:寻找两个正序数组的中位数(二)
给定两个大小分别为 m 和 n 的正序(从小到大)数组nums1 和nums2。
请你找出并返回这两个正序数组的 中位数 。
算法的时间复杂度应该为 O(log (m+n)) 。
/**
* 寻找两个正序数组的中位数
* 给定两个大小分别为 m 和 n 的正序(从小到大)数组nums1 和nums2。请你找出并返回这两个正序数组的 中位数 。
*
* 算法的时间复杂度应该为 O(log (m+n)) 。
*/
package com.my.test;
//该算法的时间复杂度为0(m+n)
public class FindMediaNumber {
public static void main(String[] args) {
int[] num1 = {1,3,5,7,9};
int[] num2 = {2,4,6};
System.out.println(FindMediaNumber(num1, num2));
}
public static double FindMediaNumber(int[] num1, int[] num2){
int m = num1.length;
int n = num2.length;
double media_num;
//如果数组1为空,则直接返回数组2的中位数
if(m == 0){
if(n%2 == 0){
media_num = (num2[n/2-1]+num2[n/2])/2.0;
} else {
media_num = num2[n/2];
}
return media_num;
}
//如果数组2为空,则直接返回数组1的中位数
if(n == 0){
if(m%2 == 0){
media_num = (num1[m/2-1]+num1[m/2])/2.0;
} else {
media_num = num1[m/2];
}
return media_num;
}
//合并两个数组
int[] combine = new int[m+n];
int count = 0;
int i = 0;
int j = 0;
while(count != (m+n)){
if (i == m) {
while(j != n){
combine[count++] = num2[j++];
}
break; //已完成合并,跳出while循环
}
if(j == n){
while (i != m){
combine[count++] = num1[i++];
}
break; //已完成合并,跳出while循环
}
//从两个数组中遍历元素,进行对比,将较小的元素放入新数组
if(num1[i] < num2[j]){
combine[count++] = num1[i++];
}else {
combine[count++] = num2[j++];
}
}
//完成数组合并后,从新数组中查找中位数
if((m+n)%2 == 0) {
media_num = (combine[(m + n) / 2 - 1] + combine[(m + n) / 2]) / 2.0;
} else {
media_num = combine[(m+n)/2];
}
return media_num;
}
}
运行结果:
4.5
Process finished with exit code 0
7. 题目:字符串转换整数 (atoi)
具体要求:
请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。
函数 myAtoi(string s) 的算法如下:
(1)读入字符串并丢弃无用的前导空格
(2)检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
(3)读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串其余部分将被忽略。
(4)将前面步骤读入的这些数字转换为整数(即,"123" -> 123, "0032" -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。
(5)如果整数数超过 32 位有符号整数范围 [−231, 231 − 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −231 的整数应该被固定为 −231 ,大于 231 − 1 的整数应该被固定为 231 − 1 。
(6)返回整数作为最终结果。
注意:
本题中的空白字符只包括空格字符 ' ' 。
除前导空格或数字后的其余字符串外,请勿忽略 任何其他字符。
假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231, 231 − 1]。如果数值超过这个范围,请返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。
代码演示:
补充知识点:
(1)在JAVA中,因为对char类型字符运行时,直接当做ASCII表中对应的整数来对待。所以char可以直接转成int,得到的就是ASCII中对应的数字。所以不能直接转成int;所可以直接将char转成String,再转成int。JAVA中,char是一个基本类型(基本类型只能由基本类型强制转换),String是一个引用类型。推荐使用valueOf这个方法进行转换。
package com.my.test;
public class MyAtoi {
public static void main(String[] args) {
String str = " 666 words and 987";
System.out.println("原始字符串为:" + str);
System.out.print("转换后的数值为: ");
System.out.println(myAtoi(str));
}
public static int myAtoi(String str){
//字符串为空的处理
if(str==null || str.equals("") || str.trim().equals("")){
return 0;
}
char[] chars = str.trim().toCharArray(); //字符串去掉前后的空格之后,转为字符数组
int index = 0;
boolean judge = true; //标识正数或负数
if(chars[0]=='+' || chars[0]=='-'){ //去除空格后,如果第一位是符号位:正号负号
if(chars[0]=='-'){
judge = false;
}
index++;
}
int sum = 0;
//int count = 0;
while(index<chars.length && Character.isDigit(chars[index])){ //除了符号位之外,开始遍历字符数组,直到遍历数组结束或者遇到非数值
int num = chars[index] - '0'; //char转为int的一种方式
//int num = Integer.parseInt(String.valueOf(chars[index])); //char转为int的另一种方式
if(sum > (Integer.MAX_VALUE-num)/10){ //判断加上该数字后是否超过最大值
if(judge){
return Integer.MAX_VALUE;
}else {
return Integer.MIN_VALUE;
}
}
//如果没超过最大值,需要求和处理
sum = sum*10 + num;
index++;
//count++;
}
//如果符号位是负号,则最后的结果是负数
if(!judge){
sum = -sum;
}
return sum;
}
}
运行结果:
原始字符串为: 666 words and 987
转换后的数值为: 666Process finished with exit code 0
8. 题目:整数反转
具体要求:
给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。
如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] ,就返回 0。
假设环境不允许存储 64 位整数(有符号或无符号)。
代码演示:
package com.my.test;
public class IntReverse {
public static void main(String[] args) {
int num = -123;
System.out.print("原始数值为:");
System.out.println(num);
System.out.print("反转后的数值为:");
System.out.println(intReverse(num));
}
public static int intReverse(int num){
long result = 0;
long min = -2147483648; //有符号整数的范围 [−231, 231 − 1], 2的31次幂
long max = 2147483647;
//使用Java里的StringBuffer类,该类中提供反转字符串的方法,先将整数转换为字符串,然后进行反转操作,再转换回整数后输出
StringBuffer sb = new StringBuffer();
sb.append(num); //整数转为字符串
if(num > 0){
sb.reverse(); //反转字符串
for(int i=0; i<sb.length(); i++){ //字符串转为整数
int n = sb.charAt(i) - '0';
result = result*10 + n;
}
if(result<max){ //如果整数没超过最大值
return (int) result;
} else {
return 0;
}
} else if(num < 0){
sb.reverse(); //反转字符串
for(int j=0; j<sb.length()-1; j++){ //字符串转为整数
int m = sb.charAt(j) - '0';
result = result*10 + m;
}
if((0-result)>min){ //如果整数没小于最小值
return (int) (0-result);
} else {
return 0;
}
} else {
return 0;
}
}
}
运行结果:
原始数值为:-123
反转后的数值为:-321Process finished with exit code 0