赞
踩
题目链接:力扣·两数之和·简单
- 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];
- }
- }
初始思路:把两个数读出来直接加,不行,太多错误,会导致无法进位(我他*&*()*反正就是不能进位,改成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;
- }
- }
题目链接:
自我解题方法(错)(语法虽然没有毛病了,思路也没毛病,但运算结果就是不对。呵。)
- 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;
- }
- }
用到的主要结构:哈希表
【主要思想】
遍历字符串,每出现一个没见过的字符,就将其加入哈希表;哈希表中只保存每个元素第一次出现的位置。
如果在遍历字符串时,发现该元素已经出现过了,那么就查找哈希表,将(第一次出现的位置下标,当前下标)这个子字符串提取出来,判断这个子字符串是不是回文串。
如果是,则判断是否需要更新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;
- }
- }
-
-
【原题地址】
【个人思路】
我的思路就是用双重循环进行暴力破解。每次遍历时,我只关心比我矮的垂线,因为这个比我矮的垂线会决定水位的高度,而我们之间下标差的绝对值就是水位的宽度。
故,暴力破解,高效完美。
但是力扣里面的输入例子里,非要给一个巨大的输入,你他喵的返回值就是个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;
- }
- }
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。