1. 两数之和·哈希表
题目链接:力扣·两数之和·简单
import java.util.HashMap;
class Solution {
public int[] twoSum(int[] nums, int target) {
//创建哈希表
HashMap<Integer,Integer> map = new HashMap<>();
//向哈希表中录入元素
for(int i=0;i<nums.length;i++)
{
map.put(nums[i],i);
}
//寻找固定值
for(int j=0;j<nums.length;j++)
{
if(map.containsKey(target-nums[j]))//找到了,返回两个下标
{
int index = map.get(target-nums[j]);
if(j!=index) return new int[]{j,index};
}
}
//要有一个出口(返回空数组)
return new int[0];
}
}
2. 两数之和
初始思路:把两个数读出来直接加,不行,太多错误,会导致无法进位(我他*&*()*反正就是不能进位,改成long , double都不行)
/**
* 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; }//链接函数
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
//读数l1,存入x
int i=1;
int x=0;
while(l1 != null){
x = x + l1.val*i;
i = i*10;
l1 = l1.next;
}
//读数l2,存入y
i=1;
int y=0;
while(l2 != null){
y= y + l2.val*i;
i = i*10;
l2 = l2.next;
}
//加和
int z = x+y;
//分离数位,尾插法建立链表
ListNode head = null;//建立头结点
ListNode tail = null;//建立尾结点
//特殊处理:如果和为0
if(z==0)
{
head = new ListNode(0);
}
//正常情况
while(z!=0){
if(head == null)
{
head = tail = new ListNode(z%10);
}
else{
tail.next = new ListNode(z%10);
tail = tail.next;
}
z = z/10;
}
//返回头指针
return head;
}
}
思路2·模拟进位
【个人超级复杂版进位操作(数字大的时候不行)】
/**
* 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; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
//建立和链表
ListNode head = null;
ListNode tail = null;
//设定一个计数器i,和一个代表乘以几个10的计数器,以及一个进位记录jin
int i = 0;
int jin = 0;
//同步从个位读取两个链表,直到其中一个停止
while(l1!=null || l2!=null)
{
int x = l1.val + l2.val;
int x0=x;
//建立新链表
if(head==null)
{
head = tail = new ListNode(x%10+jin);
}
else{
tail.next = new ListNode(x%10+jin);
tail = tail.next;
}
//计算下次是否需要进位
if(x0>9)//需要进位
jin = 1;
else//不需要进位
jin = 0;
//继续循环
l1 = l1.next;
l2 = l2.next;
}
//两个链表其中一个先终止了,把剩下的那个链表直接接入结果链表
if(l1!=null)
{
while(jin!=0 && l1!= null)
{
int x = l1.val + jin;
int x0=x;
tail.next = new ListNode(x%10);
tail = tail.next;
//判断下一位需不需要进位
//计算下次是否需要进位
if(x0>9)//需要进位
jin = 1;
else//不需要进位
jin = 0;
l1 = l1.next;
}
if(jin!=0 && l1==null)//进位进出多一位的情况
{
tail.next = new ListNode(1);
tail = tail.next;
}
if(jin==0 && l1!=null)//需要把后续连入的情况
{
tail.next = l1;
}
}
if(l2!=null)
{
while(jin!=0 && l2!= null)
{
int x = l2.val + jin;
int x0=x;
tail.next = new ListNode(x%10);
tail = tail.next;
//判断下一位需不需要进位
//计算下次是否需要进位
if(x0>9)//需要进位
jin = 1;
else//不需要进位
jin = 0;
l2 = l2.next;
}
if(jin!=0 && l2==null)//进位进出多一位的情况
{
tail.next = new ListNode(1);
tail = tail.next;
}
if(jin==0 && l2!=null)//需要把后续连入的情况
{
tail.next = l2;
}
}
return head;
}
}
答案简洁版进位
重点就在于,先结束的链表用0补足
/**
* 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; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
//新建链表,给出头尾指针
ListNode head = null, tail = null;
//carry变量用来记录进位,需要进位则为1,否则为0
int carry = 0;
//两个链表只要还有一个非空,就继续操作
while (l1 != null || l2 != null) {
//这个方法里最重要的地方就在于,要用0补足先空了的链表
int n1 = l1 != null ? l1.val : 0;
int n2 = l2 != null ? l2.val : 0;
//计算新链表当前位的值,并建立链表
int sum = n1 + n2 + carry;
if (head == null) {
head = tail = new ListNode(sum % 10);
} else {
tail.next = new ListNode(sum % 10);
tail = tail.next;
}
carry = sum / 10;//计算进位
//推动链表向下运算
if (l1 != null) {
l1 = l1.next;
}
if (l2 != null) {
l2 = l2.next;
}
}
//如果都算完了还有进位,则意味着要多出一位,因为是加法,所以多出来的一位肯定是1
if (carry > 0) {
tail.next = new ListNode(carry);
}
return head;
}
}
3.最长不重复子串·队列问题·滑动窗口
题目链接:
自我解题方法(错)(语法虽然没有毛病了,思路也没毛病,但运算结果就是不对。呵。)
import java.util.LinkedList;
import java.util.Queue;
class Solution {
public int lengthOfLongestSubstring(String s) {
//建立一个队列
Queue<String> queue = new LinkedList();
//遍历字符串,送入队列并计数
int len = 1;
int max = len;
int first = 1;
for(int i=0;i<s.length();i++)
{
//如果是第一个元素,直接入队
if(first == 1)
{
first = 0;
queue.offer(s.substring(i,i+1));//入队
}
//非首元素
else{
//如果和队首元素相同,得到当前不重复子串长度
if(s.substring(i,i+1)==queue.element())
//if(queue.element().equals(s.substring(i,i+1)))
{
//首先,进行不重复子串长度最大值比较
if(len > max)
{
max = len;//更新max值
len = 1; //len重新计数
}
//然后,弹出队首元素
String del = queue.poll();
}
else{//不相同,则将该元素入队并计数
queue.offer(s.substring(i,i+1));//入队
len++;//不重复子串长度计数
}
}
}
if(len>max)//防止最大不重复子串在最后
max = len;
//返回max值
return max;
}
}
正解:
class Solution {
public int lengthOfLongestSubstring(String s) {
// 哈希集合,记录每个字符是否出现过
Set<Character> occ = new HashSet<Character>();
int n = s.length();
// 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
int rk = -1, ans = 0;
for (int i = 0; i < n; ++i) {
if (i != 0) {
// 左指针向右移动一格,移除一个字符
occ.remove(s.charAt(i - 1));
}
while (rk + 1 < n && !occ.contains(s.charAt(rk + 1))) {
// 不断地移动右指针
occ.add(s.charAt(rk + 1));
++rk;
}
// 第 i 到 rk 个字符是一个极长的无重复字符子串
ans = Math.max(ans, rk - i + 1);
}
return ans;
}
}
6. 最长回文子串
用到的主要结构:哈希表
【主要思想】
遍历字符串,每出现一个没见过的字符,就将其加入哈希表;哈希表中只保存每个元素第一次出现的位置。
如果在遍历字符串时,发现该元素已经出现过了,那么就查找哈希表,将(第一次出现的位置下标,当前下标)这个子字符串提取出来,判断这个子字符串是不是回文串。
如果是,则判断是否需要更新max值(最长回文串长度值);如果不是,则继续向下便利字符串。
(为了保证哈希表里只保存每个元素第一次出现的位置,只有当该元素不再哈希表中时才向内添加,否则不添加。)
【需要进行的特殊情况处理】
① 整个字符串无重复的情况——哈希表长度为零,返回第一个元素即可;
② 整个字符串全是重复的情况——哈希表为长度为1,直接返回整个字符串即可;
代码记录:
import java.util.HashMap;
class Solution {
public String longestPalindrome(String s) {
//建立哈希表,存储内容为字符元素及其下标
HashMap<Character,Integer> map = new HashMap<>();
int max = 0;
int[] res = {0,0};//保存最长字符串的两个下标
//遍历字符串,并存入哈希表
int len = s.length();
//特殊情况处理——如果该字符串中没有重复元素,那么就返回第一个字符值
boolean nosame = true;
//遍历字符串
for(int i=0;i<len;i++)
{
//判断哈希表中是否已经有该元素
if(map.containsKey(s.charAt(i))){
nosame=false;
//如果有该元素,则找到该元素第一次出现的位置
int x=map.get(s.charAt(i));
//判断该子字符串是否为回文串,如果是,则计数
//首先截取该子串
String s1 = s.substring(x,i+1);//因为是前闭后开
//因为存在溢出问题,所以不截取该子串呢?
//判断是否是回文串
int i1=x;//头指针
int j1=i;//尾指针
boolean hui = true;
while(i1 < j1+1)
{
if(s.charAt(i1)!=s.charAt(j1))
{
hui = false;
break;
}
else{
i1++;
j1--;
}
}
//如果是回文串,更新max
if(hui == true)
{
int lens1 = s1.length();
if(lens1 > max)
{
max = lens1;
res[0]=x;
res[1]=i+1;
}
}
//如果当前元素为重复元素,那么不存入当前元素,即可保证哈希表中记录的是该元素第一次出现的位置
}
//如果该元素未重复,则将元素当前位置插入哈希表;
map.put(s.charAt(i),i);
}
//无重复字符的特殊处理
if(nosame == true)
{
return s.substring(0,1);
}
//全重复字符的特殊处理
if(map.size()==1)
{
return s;
}
//返回最长回文子串
return s.substring(res[0],res[1]);
}
}
此题力扣的官方解法是动态规划,动态规划上学的时候我就没学明白,放在这里供大家参考吧。
class Solution {
public String longestPalindrome(String s) {
if (s == null || s.length() < 1) {
return "";
}
int start = 0, end = 0;
for (int i = 0; i < s.length(); i++) {
int len1 = expandAroundCenter(s, i, i);
int len2 = expandAroundCenter(s, i, i + 1);
int len = Math.max(len1, len2);
if (len > end - start) {
start = i - (len - 1) / 2;
end = i + len / 2;
}
}
return s.substring(start, end + 1);
}
public int expandAroundCenter(String s, int left, int right) {
while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
--left;
++right;
}
return right - left - 1;
}
}
11.盛最多水的容器
【原题地址】
【个人思路】
我的思路就是用双重循环进行暴力破解。每次遍历时,我只关心比我矮的垂线,因为这个比我矮的垂线会决定水位的高度,而我们之间下标差的绝对值就是水位的宽度。
故,暴力破解,高效完美。
但是力扣里面的输入例子里,非要给一个巨大的输入,你他喵的返回值就是个Int,整那么大谁能不溢出?!
哼。
在此记录一下我的暴力破解代码:
import java.lang.Math;
class Solution {
public int maxArea(int[] height) {
//暴力破解法
//遍历数组,每次只关心值比当前值小的垂线,然后计算面积,不断更新迭代面积的最大值
int max = 0;
for(int i=0;i<height.length;i++)
{
for(int j=0;j<height.length;j++)
{
if(height[j]<height[i]+1)//如果j的垂线比i矮(或相等),那么它将决定水位的高度
{
int size = height[j]*Math.abs(j-i); //计算面积
if(size>max)
{
max = size;//更新max值
}
}
}
}
//返回最大值
return max;
}
}
力扣官方的思路是这样的:
设置两个指针,一个头一个尾,每次就算这两个指针组成的长方体的面积;每次只移动比较矮的那个垂线的指针。
emmm我打了一遍代码,这次倒是通过了。不得不说官方这个时间复杂度确实小的多,只进行一次遍历。
import java.lang.Math;
class Solution {
public int maxArea(int[] height) {
int i=0;//设置头指针
int j=height.length-1;//设置尾指针
int max = 0;
int size = 0;
while(i<j) //两指针交汇即为遍历完整个链表
{
size = Math.min(height[i],height[j])*(j-i);//两个数里更小的那个决定水位高度
if(size > max)
{
max = size;
}
//只移动较小值的指针
if(Math.min(height[i],height[j])==height[i])
{
i++;
}
else{
j--;
}
}
return max;
}
}