链表相加 addListNode(LeetCode)
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
// Definition for singly-linked list.
// #[derive(PartialEq, Eq, Clone, Debug)]
// pub struct ListNode {
// pub val: i32,
// pub next: Option>
// }
//
// impl ListNode {
// #[inline]
// fn new(val: i32) -> Self {
// ListNode {
// next: None,
// val
// }
// }
// }
impl Solution {
pub fn add_two_numbers(l1: Option>, l2: Option>) -> Option> {
}
}
查找不重复的字符 uniqueChar
从给定的字符串中查找给定字符出现的次数,判断次数是否唯一
测试字符串slice
slice字符串时带等号和不带的区别
由于算法相关的问题都是直接网上提交运行,不再单独建立项目
寻找两个有序数组的中位数
给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。
请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1 和 nums2 不会同时为空。
示例 1:
nums1 = [1, 3]
nums2 = [2]
则中位数是 2.0
示例 2:
nums1 = [1, 2]
nums2 = [3, 4]
则中位数是 (2 + 3)/2 = 2.5
我的解法(不清楚复杂度的问题,过了,但是不知道是否符合复杂度要求)
impl Solution {
pub fn find_median_sorted_arrays(nums1: Vec, nums2: Vec) -> f64 {
let a=nums1.len();
let b=nums2.len();
let l= if a>b{a}else{b};
let mut v: Vec = Vec::new();
for i in (0..l){
if let Some(n)=nums1.get(i){
v.push(*n);
if let Some(m)=nums2.get(i){
v.push(*m);
}
}else{
if let Some(m)=nums2.get(i){
v.push(*m);
}
}
}
v.sort();
let ll=v.len();
let mut f:f64=0.0;
if(ll%2==0){
f=((v[v.len()/2-1] as f64)+(v[v.len()/2] as f64))/2.0;
}
else{
f=v[(v.len()-1)/2] as f64
}
f
}
}
运行时间为0的大神解法
use std::mem;
impl Solution {
pub fn find_median_sorted_arrays(nums1: Vec, nums2: Vec) -> f64 {
let (mut a , mut b) = (&nums1, &nums2);
let (mut m, mut n) = (a.len(), b.len());
if m > n {
mem::swap(&mut a, &mut b);
mem::swap(&mut m, &mut n);
}
let (mut imin, mut imax, halflen) = (0, m, (m+n+1)/2);
while imin <= imax{
let i = (imin + imax) / 2;
let j = halflen - i;
if i < imax && b[j-1] > a[i] {
imin = i + 1;
}else if i > imin && a[i -1] > b[j] {
imax = i - 1;
}else{
let (maxleft, minright);
if i == 0 {
maxleft = b[j-1];
}else if j == 0 {
maxleft = a[i-1];
}else{
maxleft = a[i-1].max(b[j-1]);
}
if(m + n) % 2 == 1{
return maxleft as f64;
}
if i == m {
minright = b[j];
}else if j == n {
minright = a[i];
}else{
minright = b[j].min(a[i]);
}
return (maxleft + minright) as f64 / 2.0 ;
}
}
return 0.0;
}
}
最长回文串
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。
示例 2:
输入: "cbbd"
输出: "bb"
分析:
这个问题难度定位为中等,我倒是觉得比一般的困难还要麻烦,也可能是不熟悉RUST的原因。情况分析倒是很快出来了,程序一直跑不通,前后折腾了几个小时。
后面查资料发现了一个相当NB的马拉车算法,没详细看,感觉有点麻烦。等有时间再去肝一下。
没有系统的学过算法,按照数学分类的方式来的:
长度为0或1,直接返回
长度为2,判断是否相同,相同则直接返回
长度大于2时,先判断0,1是否相同,是的话初始串长为2,串头为0
这样的好处是对每一个字符,只需要获取已自身为中心和(自身+身后)为中心的回文串最大长度,否则加上(自身+身前)为中心的话,就会有重复操作
从1开始循环,依次获取以每个字符本身 以及 (自身+身后)为中心查找最长的回文串,记录其中最长的串长度和串头
我的代码,耗时8ms,内存2.1M
impl Solution {
pub fn longest_palindrome(s: String) -> String {
if(s.len()<2){
return s;
}
let mut ss:Vec=Vec::new();
for c in s.chars(){
ss.push(c as i32);
}
let len:usize=s.len() as usize;
//最大长度,最小为1
let mut max=1;
let mut b=0;
//前2个为相同的情况
if(s[0..1]==s[1..2]){
max=2;
b=0;
}
//从第二个开始,做i为中心和[i,i+1]为中心查找
for i in (1..len){
let mut j:usize=i as usize;
let mut k:usize=i as usize;
let mut l=0;
let mut p:usize=i as usize;
let mut q:usize=i as usize;
let mut m:usize=0;
//已自身为中心
j-=1;
k+=1;
while(j>=0&&k<=(len-1)){
if(&ss[j]==&ss[k]){
if(j==0||k==len-1){
l=2*(m as i32+1)+1;
m=0;
if(l>max as i32){max=l as usize;b=j;}
break;
}
m+=1;
j-=1;
k+=1;
}else{
l=2*(m as i32+1)-1;
m=0;
if(l>max as i32){max=l as usize;b=j+1;}
break;
}
}
//已自身和后一个为中心
q+=1;
while(p>=0&&q<=(len-1)){
if(&ss[p]==&ss[q]){
if(p==0||q==len-1){
l=2*(i as i32-p as i32+1);
if(l>max as i32){max=l as usize;b=p;}
break;
}
m+=1;
p-=1;
q+=1;
}else{
l=2*(m as i32);
if(l>max as i32){max=l as usize;b=p+1;}
break;
}
}
}
(&s[b..(b+max)]).to_string()
}
}
大神的代码 0ms,马拉车算法
impl Solution {
pub fn longest_palindrome(s: String) -> String {
let mut max_sub_str = "".to_string();
if s.len() < 1 {
return max_sub_str;
}
let mut str_ary = vec!['#'];
for c in s.chars(){
str_ary.push(c);
str_ary.push('#');
}
let str_ary_len = str_ary.len() as i32;
let mut radius = vec![0;str_ary_len as usize];
let (mut r, mut c , mut max) = (-1, -1, 0);
for i in 0..str_ary_len {
let mut k = if r > i {
radius[ (2 * c - i) as usize].min(r - i + 1)
}else{
1
};
while i + k < str_ary_len && i - k > -1 && str_ary[(i - k) as usize] == str_ary[(i + k) as usize]{
k += 1;
}
if i + k > r {
r = i + k - 1;
c = i;
}
max = max.max(k);
radius[i as usize] = k;
}
for (key, &val) in radius.iter().enumerate() {
if val == max {
max_sub_str = str_ary[key-(max as usize -1)..key+max as usize].iter()
.filter(|&x| *x != '#').collect::();
}
}
max_sub_str
}
}
大神的代码1 4ms
impl Solution {
pub fn longest_palindrome(s: String) -> String {
let mut max_length = 0;
let mut palindrome :String = String::from("");
let bytes = s.as_bytes();
let mut i = 0;
while i < bytes.len() as i32 - max_length {
let mut j:i32 = i.clone();
let mut k:i32 = i.clone();
let mut palindrome_size1 : i32 = 0;
let mut palindrome_size2 : i32 = 0;
while j >= 0 && k < s.len() as i32 && bytes[j as usize] == bytes[k as usize] {
palindrome_size1 += 1;
j -=1;
k +=1;
}
j = i.clone();
k = i.clone() + 1;
while j >= 0 && k < s.len() as i32 && bytes[j as usize] == bytes[k as usize] {
palindrome_size2 += 1;
j -=1;
k +=1;
}
if max_length < palindrome_size1 && palindrome_size1 > palindrome_size2 ||
max_length == palindrome_size1 && palindrome_size1 > palindrome_size2 && palindrome.len() as i32 % 2 != 0{
palindrome = String::from(&s[(i+1-palindrome_size1) as usize .. (i+palindrome_size1) as usize]);
max_length = palindrome_size1;
} else if max_length <= palindrome_size2 && palindrome_size2 >= palindrome_size1{
palindrome = String::from(&s[(i+1-palindrome_size2) as usize .. (i+1+palindrome_size2) as usize]);
max_length = palindrome_size2;
}
i += 1;
}
palindrome
}
}
整数反转
给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
示例 1:
输入: 123
输出: 321
示例 2:
输入: -123
输出: -321
示例 3:
输入: 120
输出: 21
注意:
假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−231, 231 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。
没想到什么好方法,直接用f64开始蛮干
我的代码
impl Solution {
pub fn reverse(x: i32) -> i32 {
let mut n:f64=0.0;
let mut y=x;
let mut t=0;
let mut q=1;
let mut v= vec![];
while (y/10)!=0 {
v.push(y%10);
y=y/10;
t+=1;
q*=10;
}
v.push(y);
for i in (0..=t){
n += (v[i] as f64) * q as f64;
q/=10;
t-=1;
}
if(n>(2147483647 as f64)||n
0
}else{
n as i32
}
}
}
没发现大神代码,估计太简单,大神不屑出手
字符串转数字(atoi)
请你来实现一个 atoi 函数,使其能将字符串转换成整数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。
当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。
该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。
在任何情况下,若函数不能进行有效的转换时,请返回 0。
说明:
假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231, 231 − 1]。如果数值超过这个范围,请返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。
示例 1:
输入: "42"
输出: 42
示例 2:
输入: " -42"
输出: -42
解释: 第一个非空白字符为 '-', 它是一个负号。
我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。
示例 3:
输入: "4193 with words"
输出: 4193
解释: 转换截止于数字 '3' ,因为它的下一个字符不为数字。
示例 4:
输入: "words and 987"
输出: 0
解释: 第一个非空字符是 'w', 但它不是数字或正、负号。
因此无法执行有效的转换。
示例 5:
输入: "-91283472332"
输出: -2147483648
解释: 数字 "-91283472332" 超过 32 位有符号整数范围。
因此返回 INT_MIN (−231) 。
我的代码:0 ms 1.9M
impl Solution {
pub fn my_atoi(str: String) -> i32 {
let s=str.trim();
let mut n:f64=0.0;
let mut v:Vec=Vec::new();
let mut k=0;
let mut t=0;
if s.is_empty(){
return 0;
}
let h:char=s.as_bytes()[0] as char;
if !h.is_numeric() && h!='-'&& h!='+'{
return 0;
}else if (h=='-'){
k=-1;
}else if (h=='+'){
k=1;
}
let mut len:f64=0.1;
for c in s.chars(){
match c{
'0'...'9'=>{
len*=10 as f64;
v.push(c as u8);
},
'-'=>if k==-1&& t==0{
t=1;
}else{
t=2;
},
'+'=>if k==1&& t==0{
t=1;
}else{
t=2;
},
_=>{break;}
}
if(t>1){
break;
}
}
if k==0{k=1;}
for i in &v{
n+= (*i-48) as f64 * len;
len /=10.0;
}
if(k==1&&n>2147483647 as f64){
2147483647
}else if(k==-1&&n>2147483647 as f64){
-2147483648
}else{
(n*k as f64) as i32
}
}
}
大神代码:
impl Solution {
pub fn my_atoi(s: String) -> i32 {
let mut result = 0i32;
let mut iter = s.chars()
.skip_while(|c| c.is_whitespace())
.peekable();
let sign = match iter.peek() {
Some('-') => {iter.next();-1},
Some('+') => {iter.next();1},
Some(c) if c.is_ascii_digit() => 1,
_ => return 0,
};
for c in iter {
if c.is_ascii_digit() {
let d = c.to_digit(10).unwrap() as i32;
result = result.saturating_mul(10)
.saturating_add(sign*d);
} else {
break
}
}
result
}
}
三数之和
给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
这个题题库给出的难度等级是中等,我感觉比不少困难的题目还要难,感受到了智商被碾压的痛苦...
思路一:
转换为两数之和,再和第三个数匹配;最后去重
哦豁~超时了
代码(比较垃圾,仅为实现功能,未考虑优化):
impl Solution {
pub fn three_sum(nums: Vec) -> Vec> {
let mut vv:Vec>=vec![];
let mut s=String::new();
let len=nums.len();
if len<3{ return vv;}
let mut vt:Vec=vec![];
let mut i=0;
let mut m=0;
let mut n=0;
while i
m=nums[i];
let mut j=i+1;
while j
n=nums[j];
if m>n{
vt.push((n,m,i as i32,0-m-n,j as i32));
}else{
vt.push((m,n,i as i32,0-m-n,j as i32));
}
j+=1;
}
//println!("{:?}",vt);
i+=1;
}
//println!("{:?}",vt);
for t in &vt{
let index=t.2;
let index1=t.4;
let x=t.0;
let y=t.1;
let z=t.3;
for j in(0..len){
if j as i32!=index && j as i32!=index1&& nums[j]==z{
let mut ss= String::new();
if(z
ss= format!("({}{}{})",z,x,y);
}else if(z>y){
ss= format!("({}{}{})",x,y,z);
}else{
ss= format!("({}{}{})",x,z,y);
}
if(s.find(&ss)==None){
s.push_str(&ss);
vv.push([t.0,t.1,t.3].to_vec());
}
break;
}
}
}
vv
}
}
后面有折腾了几个小时优化,还是不行,感觉此路不通,换思路
思路二 直接循环:
排序
开始循环:
可行,耗时768ms,内存3.3M,获取可变vec的部分应该有方法减少耗时(这样产生新的vec丑的没道理)
impl Solution {
pub fn three_sum(nums: Vec) -> Vec> {
let mut vn:Vec=Vec::new();
let mut vv:Vec>=vec![];
if nums.len()<3{ return vv;}
//vn=nums; 查到的新方法,或者直接使用
// let mut vn=nums;
for it in &nums{
vn.push(*it);
}
//使用不稳定排序sort_unstable(),这个通常比sort()要快点
vn.sort_unstable();
let l=vn.len();
//println!("vn:{:?}",vn);
//用来记录第一个数的值,防止连续多个相同的x产生重复
let mut key=-2147483648;
//用来记录第二个数的值,防止连续多个相同的x产生重复
let mut kkk=-2147483648;
for mut i in (0..l-2){
let mut k=0;
let mut x=vn[i];
if x==key{
i+=1;
continue;
}else{
key=x;
}
let mut j=i+1;
//最小值大于0,结束循环
if x>0{ break;}
let mut y=0;
let mut z=0;
while j
//println!("jjj,{},{},{},y-->{}",i,j,k,vn[j]);
y=vn[j];
if y==kkk{
j+=1;
continue;
}else{
kkk=y;
}
z=0-x-y;
k=j+1;
// k部分的循环可以用下面的3行代替,但是时间会增加
//if vn[k..l].contains(&z){
// vv.push([x,y,z].to_vec());
//}
while(k
// println!("kkk,{},{},{}",i,j,k);
let mut p=vn[k];
if p
k+=1;
}else if p==z{
//println!("vv.push:{:?},{},{},{}",vv,i,j,k);
vv.push([x,y,z].to_vec());
break;
}else{
break;
}
}
j+=1;
}
//println!("vv:{:?},{},{},{}",vv,i,j,k);
i+=1;
}
vv
}
}
大神代码(双指针) 20ms,4.5M:
impl Solution {
pub fn three_sum(nums: Vec) -> Vec> {
let nums_len = nums.len();
if nums_len < 3 {
return vec![];
}
let mut nums = nums;
nums.sort();
let mut result: Vec> = vec![];
for i in 0..nums_len {
if nums[i] > 0 {
break;
}
if i > 0 && nums[i] == nums[i - 1] {
continue;
}
let mut l = i + 1;
let mut r = nums_len - 1;
while l < r {
let sum = nums[i] + nums[l] + nums[r];
if sum == 0 {
result.push(vec![nums[i], nums[l], nums[r]]);
while l < r && nums[l] == nums[l + 1] {
l += 1;
}
while l < r && nums[r] == nums[r - 1] {
r -= 1;
}
l += 1;
r -= 1;
} else if sum > 0 {
r -= 1;
} else {
l += 1;
}
}
}
return result;
}
}
(之前的都是双指针)96ms 1.8M
impl Solution {
pub fn three_sum(mut nums: Vec) -> Vec> {
let mut ret = Vec::new();
if nums.len() < 3 {
return ret;
}
nums.sort();
for i in 0..nums.len()-2 {
if i == 0 || nums[i] != nums[i-1] {
for j in i+1..nums.len()-1 {
if j == i+1 || nums[j] != nums[j-1] {
if let Ok(p) = &nums[j+1..].binary_search(&(-nums[i]-nums[j])) {
ret.push(vec![nums[i], nums[j], nums[j+1+p]]);
}
}
}
}
}
ret
}
}
大神代码(按思路一实现)152ms 0.9M:
impl Solution {
pub fn three_sum(nums: Vec) -> Vec> {
let mut counter = std::collections::HashMap::new();
for &x in &nums {
*counter.entry(x).or_insert(0) += 1;
}
let mut keys: Vec = counter.keys().cloned().collect();
keys.sort_unstable();
let mut ans: Vec> = vec![];
for i in 0..keys.len() {
for j in i..keys.len() {
let (a, b) = (keys[i], keys[j]);
let c = -(a + b);
if ! counter.contains_key(&c) {
continue;
}
if a == b && b == c && counter[&a] >= 3 {
ans.push(vec![a, b, c]);
} else if a == b && b != c && counter[&a] >= 2 {
ans.push(vec![a, b, c]);
} else if a < b && b < c {
ans.push(vec![a, b, c]);
}
}
}
ans
}
}
最接近的三数之和
给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
例如,给定数组 nums = [-1,2,1,-4], 和 target = 1.
与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).
思路:
其实和上面的三数之和类似,最快的应该还是双指针,但我还是试了一下爆破:32ms 2M
impl Solution {
pub fn three_sum_closest(nums: Vec, target: i32) -> i32 {
let len=nums.len();
if len <3{
let mut n=0;
for i in &nums{
n+=*i;
}
return n;
}
let mut nums=nums;
nums.sort_unstable();
let mut sum=nums[0]+nums[1]+nums[2];
let mut c=(sum-target).abs();
//println!("nums:{:?},sum:{},c:{}",nums,sum,c);
for mut i in 0..len-2{
let mut j=i+1;
while j
let mut k=j+1;
while k
let mut s=nums[i]+nums[j]+nums[k];
if s==target{
return target;
}
let mut cc=(s-target).abs();
if cc<=c{ c=cc; sum=s;}
k+=1;
}
j+=1;
}
i+=1;
}
sum
}
}
双指针 0ms 1.9M
impl Solution {
pub fn three_sum_closest(mut nums: Vec, target: i32) -> i32 {
let len = nums.len();
if len < 3 {
let mut n=0;
for i in &nums{
n+=*i;
}
return n;
}
nums.sort_unstable();
let mut sum = nums[0]+nums[1]+nums[2];
let mut c = (sum-target).abs();
for i in 0..len {
if i>0 && nums[i-1] > target {
break;
}
let mut l = i+1;
let mut r = len-1;
while l < r {
let s = nums[i]+nums[l]+nums[r];
let cc = (s-target).abs();
if cc < c {
if cc == 0 {
return s;
}
c = cc;
sum = s;
}
if s > target {
r-=1;
} else {
l+=1;
}
}
}
sum
}
}
其它算法(大神算法,没细看) 4ms,24.14M:
impl Solution {
pub fn three_sum_closest(mut nums: Vec, target: i32) -> i32 {
nums.sort();
let mut ret = 0;
let mut d = i32::max_value();
for i in 0..nums.len()-2 {
for j in i+1..nums.len()-1 {
let t = target - nums[i] - nums[j];
let s = &nums[j+1..];
match s.binary_search(&t) {
Ok(_) => {
return target;
},
Err(k) => {
if k < s.len() && (t - s[k]).abs() < d {
ret = nums[i] + nums[j] + s[k];
d = (ret - target).abs();
}
if k > 0 && (t - s[k-1]).abs() < d {
ret = nums[i] + nums[j] + s[k-1];
d = (ret - target).abs();
}
},
}
}
}
ret
}
}
有效的括号
给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
示例 1:
输入: "()"
输出: true
示例 2:
输入: "()[]{}"
输出: true
示例 3:
输入: "(]"
输出: false
示例 4:
输入: "([)]"
输出: false
示例 5:
输入: "{[]}"
输出: true
思路:直接push pop操作即可 0ms,2M
impl Solution {
pub fn is_valid(s: String) -> bool {
if s.len()%2==1{
return false;
}
let mut ss=String::new();
for c in s.chars(){
match c{
')'=>{
if ss.pop()!=Some('('){
return false;
}
},
']'=>{
if ss.pop()!=Some('['){
return false;
}
},
'}'=>{
if ss.pop()!=Some('{'){
return false;
}
},
_=>ss.push(c)
};
}
ss.is_empty()
}
}
删除排序数组中的重复项
给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
示例 1:
给定数组 nums = [1,1,2],
函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。
你不需要考虑数组中超出新长度后面的元素。
示例 2:
给定 nums = [0,0,1,1,1,2,2,3,3,4],
函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。
你不需要考虑数组中超出新长度后面的元素。
说明:
为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
你可以想象内部操作如下:
// nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
int len = removeDuplicates(nums);
// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。
for (int i = 0; i < len; i++) {
print(nums[i]);
}
思路一: 找出重复项,删除再返回长度 8ms,2.2M
impl Solution {
pub fn remove_duplicates(nums: &mut Vec) -> i32 {
let mut len=nums.len();
if len<2{
return len as i32;
}
let mut n=nums[0];
let mut v:Vec=vec![];
for mut i in 1..len{
println!("i:{} v:{:?}",i,v);
if nums[i]==n{
len-=1;
v.push(i as i32);
}else{
n=nums[i];
i+=1;
}
}
for mut j in 0..v.len(){
//println!("i:{} nums:{:?},v[j]:{}",j,nums,v[j]);
nums.remove(v[j] as usize-j);
}
len as i32
}
}
优化一下,缩短代码:
impl Solution {
pub fn remove_duplicates(nums: &mut Vec) -> i32 {
let mut len=nums.len();
if len<2{
return len as i32;
}
let mut n=nums[0];
let mut k=0;
for mut i in 1..len{
i= i-k;
//println!("i:{} nums:{:?}",i,nums);
if nums[i]==n{
nums.remove(i);
len-=1;
k+=1;
}else{
n=nums[i];
i+=1;
}
}
len as i32
}
}
不删,直接修改并返回长度 0ms,2.2M
impl Solution {
pub fn remove_duplicates(nums: &mut Vec) -> i32 {
let mut len=nums.len();
if len<2{
return len as i32;
}
let mut n=nums[0];
let mut k=0;
for mut i in 1..len{
//println!("i:{} nums:{:?}",i,nums);
if nums[i]==n{
len-=1;
}else{
n=nums[i];
k+=1;
nums[k]=n;
}
}
len as i32
}
}
搜索旋转排序数组
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
你可以假设数组中不存在重复的元素。
你的算法时间复杂度必须是 O(log n) 级别。
示例 1:
输入: nums = [4,5,6,7,0,1,2], target = 0
输出: 4
示例 2:
输入: nums = [4,5,6,7,0,1,2], target = 3
输出: -1
分析:不要求时间复杂度的话,直接contains即可,这里用二分查找,不清楚是否符合要求
代码 0ms,2M
impl Solution {
pub fn search(nums: Vec, target: i32) -> i32 {
let len=nums.len();
if len<1{
return -1;
}
if len==1 && nums[0]==target{
return 0;
}else if len==1 && nums[0]!=target{
return -1;
}
let mut l=0;
let mut r=len-1;
while l<=r{
if target==nums[l]{
return l as i32;
}
if target==nums[r]{
return r as i32;
}
l+=1;
r-=1;
}
-1
}
}
字符串相乘
给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。
示例 1:
输入: num1 = "2", num2 = "3"
输出: "6"
示例 2:
输入: num1 = "123", num2 = "456"
输出: "56088"
说明:
num1 和 num2 的长度小于110。
num1 和 num2 只包含数字 0-9。
num1 和 num2 均不以零开头,除非是数字 0 本身。
不能使用任何标准库的大数类型(比如 BigInteger)或直接将输入转换为整数来处理
思路:
不能用大数或转整数,考虑将乘法转换为加法计算
循环获取各位相乘的值和位数(尾部0的个数)
记入以位数为key值为value的HashSet
获取各种位数的值和进位值,生成字符串
代码 16ms 1.9M
use std::collections::HashMap;
impl Solution {
pub fn multiply(num1: String, num2: String) -> String {
if &num1=="0"||&num2=="0"{
return String::from("0");
}
if &num1=="1"{
return num2;
}
if &num2=="1"{
return num1;
}
let mut l1=num1.len();
let mut l2=num2.len();
let mut l=l1+l2-2;
let mut n1=num1.as_bytes();
let mut n2=num2.as_bytes();
let mut mp = HashMap::new();
for mut i in 0..l1{
for mut j in 0..l2{
let mut m=(n1[i] as i32-48)*(n2[j] as i32-48);
let mut n=(l-i-j) as i32;
if mp.contains_key(&n){
let p=mp.get(&n).unwrap()+m;
mp.insert(n,p);
}else{
mp.insert(n,m);
}
}
}
Self::check(mp)
}
fn check(mut mp:HashMap)->String{
let mut s=String::new();
let mut key=0;
for i in 0..mp.len(){
let mut m=mp.get(&(i as i32)).unwrap()+key;
s = (m%10).to_string()+&s;
key=m/10;
}
if key>0{
s = key.to_string()+&s;
}
s
}
}
大神算法 0ms 80M
直接按照乘法计算
impl Solution {
pub fn multiply(num1: String, num2: String) -> String {
if num1 == "0" || num2 == "0" {
return String::from("0");
}
let num1 = num1.as_bytes();
let num2 = num2.as_bytes();
let mut rst = vec!['0' as u8; num1.len() + num2.len() + 1];
let mut cur = 0;
for idx1 in (0..num1.len()).rev() {
let cur1 = num1[idx1] - '0' as u8;
let mut rst_cur = rst.len() - 1 - cur;
for idx2 in (0..num2.len()).rev() {
let cur2 = num2[idx2] - '0' as u8;
let mul = cur2 * cur1 + rst[rst_cur] - '0' as u8;
rst[rst_cur] = mul % 10 + '0' as u8;
rst[rst_cur - 1] = rst[rst_cur - 1] - ('0' as u8) + mul / 10 + '0' as u8;
rst_cur -= 1;
}
cur += 1;
}
for idx in 0..rst.len() {
if rst[idx] != '0' as u8 {
cur = idx;
break;
}
}
let rst = String::from_utf8(rst).unwrap();
rst[cur..].to_string()
}
}
全排列
给定一个没有重复数字的序列,返回其所有可能的全排列。
示例:
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
脑子不够用,时间来凑...
分别以序列中每一个元素为头处理
去头
去头后的新序列获取不同顺序的新序列组
对新序列组中的每一个序列重复上面的去头和获取序列组步骤
若新序列长度为2,返回本身和交换位置的序列
对每一个返回的序列加头
对返回的每一个序列加头,重复值不添加至返回序列组
对将返回序列组中的序列加入到返回值序列组
需要学习一下,知道用递归可以写出漂亮的代码,可是就是不知道该怎么用...
代码 8ms 2.1M
impl Solution {
pub fn permute(nums: Vec) -> Vec> {
let mut v:Vec>=vec![];
let mut num=vec![];
num.extend_from_slice(&nums);
let len=nums.len();
if len<2{
v.push(nums);
return v;
}else if len==2{
let p=nums[0];
let q=nums[1];
v.push(vec![p,q]);
v.push(vec![q,p]);
return v;
}
else{
for i in 0..len{
let mut num=vec![];
let mut vs:Vec>=vec![];
num.extend_from_slice(&nums);
vs = Self::check(i,&num);
for m in &vs{
v.push(m.to_vec());
}
}
/*let mut num=vec![];
let mut vs:Vec>=vec![];
num.extend_from_slice(&nums);
vs = Self::check(3,num);
for m in &vs{
v.push(m.to_vec());
} */
v
}
}
fn check(i:usize,nums:& Vec)->Vec>{
let mut v:Vec>=vec![];
let len=nums.len();
let mut k=vec![];
k.extend_from_slice(&nums);
let key=k[i];
if len>2{
k.remove(i);
let mut pp:Vec>=vec![];
let mut ps:Vec>=vec![];
let mut k0=vec![];
k0.extend_from_slice(&k);
ps.push(k0);
for j in 1..k.len(){
for m in 0..k.len()-1{
let mut kk=vec![];
kk.extend_from_slice(&k);
if j!=m{
kk.swap(m,j);
ps.push(kk);
}
}
}
//println!("i-->{},ps:{:?}",i,ps);
for ss in &ps{
let mut vv:Vec>=vec![];
vv=Self::check(0,&ss.to_vec());
for p in &vv{
let mut q:Vec=p.to_vec();
q.insert(0,key);
if !pp.contains(&q){
pp.push(q);
}
}
}
//println!("i-->{},pp:{:?}",i,pp);
v=pp;
}
else if len==2{
let mut kk=vec![];
kk.extend_from_slice(&k);
v.push(k);
kk.swap(0,1);
v.push(kk);
}
// println!("v------->{:?}",v);
v
}
}
稍作修改,优化部分无效代码 4ms,2.2M
impl Solution {
pub fn permute(nums: Vec) -> Vec> {
let mut v=vec![];
let len=nums.len();
if len<2{
v.push(nums);
}else if len==2{
let p=nums[0];
let q=nums[1];
v.push(vec![p,q]);
v.push(vec![q,p]);
}
else{
for i in 0..len{
let mut vs=vec![];
vs = Self::check(i,&nums);
for m in &vs{
v.push(m.to_vec());
}
}
}
v
}
fn check(i:usize,nums:& Vec)->Vec>{
let mut v=vec![];
let len=nums.len();
let mut k=vec![];
k.extend_from_slice(&nums);
let key=k[i];
if len>2{
k.remove(i);
let mut pp=vec![];
let mut ps=vec![];
for j in 1..k.len(){
for m in 0..k.len()-1{
let mut kk=vec![];
kk.extend_from_slice(&k);
if j!=m{
kk.swap(m,j);
ps.push(kk);
}
}
}
//println!("i-->{},ps:{:?}",i,ps);
for ss in &ps{
let mut vv=vec![];
vv=Self::check(0,&ss.to_vec());
for p in &vv{
let mut q=p.to_vec();
q.insert(0,key);
if !pp.contains(&q){
pp.push(q);
}
}
}
//println!("i-->{},pp:{:?}",i,pp);
v=pp;
}
else if len==2{
let mut kk=vec![];
kk.extend_from_slice(&k);
v.push(k);
kk.swap(0,1);
v.push(kk);
}
// println!("v------->{:?}",v);
v
}
}
大神代码 0ms 93.10M 直接递归,确实漂亮
impl Solution {
pub fn permute(nums: Vec) -> Vec> {
let mut ret = vec![];
let mut nums = nums;
Self::traverse(0, &mut nums, &mut ret);
ret
}
fn traverse(first: usize, cur: &mut Vec, ret: &mut Vec>) {
if first == cur.len() {
ret.push(cur.to_owned());
}
for i in first..cur.len() {
cur.swap(i, first);
Self::traverse(first + 1, cur, ret);
cur.swap(i, first);
}
}
}
最大子序和
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
进阶:
如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。
代码:0ms 2.2M
impl Solution {
pub fn max_sub_array(nums: Vec) -> i32 {
let mut m=nums[0];
let mut s=m;
let len=nums.len();
for i in 1..len{
let mut temp=m+nums[i];
if nums[i]>temp{
m=nums[i];
}else{
m=temp;
}
if s>m{
s=s;
}else{
s=m;
}
}
s
}
}
合并两个有序数组
给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。
说明:
初始化 nums1 和 nums2 的元素数量分别为 m 和 n。
你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。
示例:
输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3
输出: [1,2,2,3,5,6]
代码 0ms 2.1M
impl Solution {
pub fn merge(nums1: &mut Vec, m: i32, nums2: &mut Vec, n: i32) {
for i in 0..n as usize{
nums1[i+m as usize]=nums2[i];
}
nums1.sort();
}
}
只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1]
输出: 1
示例 2:
输入: [4,1,2,1,2]
输出: 4
代码 0ms 2.2M
impl Solution {
pub fn single_number(nums: Vec) -> i32 {
let mut nums=nums;
nums.sort();
if nums.len()==1{
return nums[0];
}
let mut i=0;
while i< nums.len()-2{
if nums[i]!=nums[i+1]{
return nums[i];
}else{
i+=2;
}
}
nums[i]
}
}
大神代码 0ms 82M
impl Solution {
pub fn single_number(nums: Vec) -> i32 {
let mut res = 0 as i32;
for i in &nums {
res ^= *i;
}
res
}
}
多数元素
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入: [3,2,3]
输出: 3
示例 2:
输入: [2,2,1,1,1,2,2]
输出: 2
代码 4ms 2.4M
use std::collections::HashMap;
impl Solution {
pub fn majority_element(nums: Vec) -> i32 {
let mut map = HashMap::new();
let len=nums.len()/2+1;
let mut n=nums[0];
for k in &nums {
let count = map.entry(k).or_insert(0);
*count += 1;
if(*count>=len){
n= *k;
break;
}
}
n
}
}
大神代码:0ms 58.54M
impl Solution {
pub fn majority_element(nums: Vec) -> i32 {
let mut nums = nums;
let len = nums.len();
nums.sort();
nums[len / 2]
}
}
存在重复元素
给定一个整数数组,判断是否存在重复元素。
如果任何值在数组中出现至少两次,函数返回 true。如果数组中每个元素都不相同,则返回 false。
示例 1:
输入: [1,2,3,1]
输出: true
示例 2:
输入: [1,2,3,4]
输出: false
示例 3:
输入: [1,1,1,3,3,4,3,2,4,2]
输出: true
代码 4ms 5.2M 使用hashmap要慢一些
use std::collections::HashMap;
impl Solution {
pub fn contains_duplicate(nums: Vec) -> bool {
let mut map = HashMap::new();
let mut b=false;
for k in &nums {
let count = map.entry(k).or_insert(0);
*count += 1;
if(*count>1){
b=true;
break;
}
}
b
}
}
大神代码 0ms 27.78M
impl Solution {
pub fn contains_duplicate(mut nums: Vec) -> bool {
if nums.len() < 2 {
return false;
}
nums.sort();
for i in 1..nums.len() {
if nums[i] == nums[i - 1] {
return true;
}
}
false
}
}
2的幂
给定一个整数,编写一个函数来判断它是否是 2 的幂次方。
示例 1:
输入: 1
输出: true
解释: 2^0 = 1
示例 2:
输入: 16
输出: true
解释: 2^4 = 16
示例 3:
输入: 218
输出: false
代码 0ms 2M
impl Solution {
pub fn is_power_of_two(n: i32) -> bool {
if n==1{
return true;
}else if n==0{
return false;
}else if n%2==1{
return false;
}else{
return Self::is_power_of_two(n/2);
}
}
}
大神代码 0ms 2M 直接位运算返回
impl Solution {
pub fn is_power_of_two(n: i32) -> bool {
return n > 0 && 0 == ((n-1) & n);
}
}
反转字符串中的单词 III
给定一个字符串,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。
示例 1:
输入: "Let's take LeetCode contest"
输出: "s'teL ekat edoCteeL tsetnoc"
注意:在字符串中,每个单词由单个空格分隔,并且字符串中不会有任何额外的空格。
代码 4ms 2.2M 分割->翻转->拼接->去尾部空格
impl Solution {
pub fn reverse_words(s: String) -> String {
let mut ss=String::new();
for word in s.split_whitespace() {
ss.push_str(&Self::reverse(word.to_string()));
}
ss.trim().to_string()
}
fn reverse(s:String)->String{
let mut ss=s;
unsafe {
let vec = ss.as_mut_vec();
vec.reverse();
ss=String::from_utf8(vec.to_vec()).unwrap();
ss.push(' ');
}
ss
}
}
大神代码 0ms 2.1M 直接干
impl Solution {
pub fn reverse_words(s: String) -> String {
let mut start_idx = 0;
let mut end_idx = 0;
let mut result = String::new();
let chars = s.as_bytes();
loop {
if end_idx == s.len() || chars[end_idx] == ' ' as u8 {
for idx in (start_idx..end_idx).rev() {
result.push(chars[idx] as char);
}
if end_idx != s.len() {
result.push(' ');
} else {
break;
}
start_idx = end_idx + 1;
}
end_idx += 1;
}
result
}
}
反转字符串
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
示例 1:
输入:["h","e","l","l","o"]
输出:["o","l","l","e","h"]
示例 2:
输入:["H","a","n","n","a","h"]
输出:["h","a","n","n","a","H"]
代码 24ms 5.3M
impl Solution {
pub fn reverse_string(s: &mut Vec) {
if s.len()>1
{
let mut r=s.len()-1;
let mut l=0;
while(l
s.swap(l,r);
l+=1;
r-=1;
}
}
}
}
其它方案:直接reverse()返回;
除自身以外数组的乘积
给定长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。
示例:
输入: [1,2,3,4]
输出: [24,12,8,6]
说明: 请不要使用除法,且在 O(n) 时间复杂度内完成此题。
进阶:
你可以在常数空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组不被视为额外空间。)
代码 4ms 3.2M
impl Solution {
pub fn product_except_self(nums: Vec) -> Vec {
let mut r:Vec=Vec::new();
let mut l:Vec=Vec::new();
let mut len=nums.len();
r.push(1);
l.push(1);
//println!("len:{}",len);
for i in 1..len{
let mut m=l[i-1]*nums[i-1];
let mut n=r[i-1]*nums[len-i];
l.push(m as i32);
r.push(n as i32);
}
//println!("l:{:?},r:{:?}",l,r);
for i in 0..len{
l[i]=l[i]*r[len-i-1];
//r.push(n as i32);
}
l
}
}
数组中的第K个最大元素
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
示例 1:
输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
示例 2:
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
说明:
你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。
代码 0ms 2.1M
impl Solution {
pub fn find_kth_largest(nums: Vec, k: i32) -> i32 {
let mut v=nums.clone();
let mut n=nums.len()-k as usize;
v.sort();
v[n]
}
}
大神代码 使用BinaryHeap,这个没看过文档,代码看不懂...下周把文档翻了看一下
use std::collections::BinaryHeap;
impl Solution {
pub fn find_kth_largest(nums: Vec, k: i32) -> i32 {
let mut heap = BinaryHeap::new();
for n in nums {
heap.push(n);
}
for _ in 0..k - 1 {
heap.pop();
}
*heap.peek().unwrap()
}
}
买卖股票的最佳时机 II
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
示例 2:
输入: [1,2,3,4,5]
输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。
因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
示例 3:
输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
代码 0ms 2.1M
impl Solution {
pub fn max_profit(prices: Vec) -> i32 {
let mut t=0;
if prices.is_empty(){
return 0;
}
let mut min=prices[0];
for i in &prices{
if *i>min{
t+=*i-min;
min=*i;
}
min=*i;
}
t
}
}
环形链表
给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
进阶:
你能用 O(1)(即,常量)内存解决此问题吗?
此问题无LeetCode无Rust选项,使用C快慢指针处理
代码 12ms 8.6M
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
bool hasCycle(struct ListNode *head) {
if( (head == NULL) || (head->next == NULL)){
return false;
}
struct ListNode* slow = head;
struct ListNode* fast = head->next;
while (slow != fast) {
if (fast == NULL || fast->next == NULL) {
return false;
}
slow = slow->next;
fast = fast->next->next;
}
return true;
}
相交的链表(C实现)
编写一个程序,找到两个单链表相交的起始节点。
如下面的两个链表:
在节点 c1 开始相交。
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
示例 2:
输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Reference of the node with value = 2
输入解释:相交节点的值为 2 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
示例 3:
输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
输入解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
解释:这两个链表不相交,因此返回 null。
思路:找出更长的链表和长度差,从链表倒序长度相同开始的地方开始循环比较
代码 48ms,15.2M
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
if(headA==NULL||headB==NULL){
return NULL;
}
struct ListNode* m = headA;
struct ListNode* n = headB;
int len=0;
int t=0;
bool b=false;
while(m->next!=NULL&&n->next!=NULL){
m=m->next;
n=n->next;
t++;
}
while(m->next!=NULL){
m=m->next;
len++;
}
while(n->next!=NULL){
n=n->next;
len++;
b=true;
}
m = headA;
n = headB;
//printf("len=%d,b=%d,t=%d",len,b,t);
if(b){
while(len>0){
n=n->next;
len--;
}
}else{
while(len>0){
m=m->next;
len--;
}
}
while(m!=n){
m=m->next;
n=n->next;
}
return m;
}
大神代码 40ms 15.2M 硬来,但是代码很漂亮
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode *a = headA;
struct ListNode *b = headB;
while (a != b) {
a = a == NULL ? headB : a->next;
b = b == NULL ? headA : b->next;
}
return a;
}
反转链表(C实现)
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
代码 4ms 7.6M 头插
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* reverseList(struct ListNode* head){
if(!head){return NULL;}
struct ListNode *m = NULL;
struct ListNode *n;
while (head != NULL) {
n = head;
head = head->next;
//头插
n->next = m;
m = n;
}
return m;
}
代码 8ms 7.7M 递归
struct ListNode* reverseList(struct ListNode* head){
if(head == NULL || head->next == NULL){
return head;
}
struct ListNode* n = reverseList(head->next);
head->next->next = head;
head->next = NULL;
return n;
}
二叉搜索树的最近公共祖先(C实现)
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]
示例 1:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6
解释: 节点 2 和节点 8 的最近公共祖先是 6。
示例 2:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
输出: 2
解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。
说明:
所有节点的值都是唯一的。
p、q 为不同节点且均存在于给定的二叉搜索树中。
分析:题目的关键在于搞清楚啥是二叉搜索树,知道了就简单,不知道就只能暴力搜索
百度百科
二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。
代码: 44ms 30.3M
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q) {
if(root==NULL||root==p||root==q){
return root;
}
while(root){
if(p->valval&&q->valval){
root=root->left;
}else if(p->val>root->val&&q->val>root->val){
root=root->right;
}else{
return root;
}
}
return root;
}
大神代码 使用递归 8ms
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q) {
int rv = root->val, pv = p->val, qv = q->val;
if (rv == pv || rv == qv) return root;
if ((rv < pv && rv > qv) || (rv > pv && rv < qv)) return root;
if (rv < pv) return lowestCommonAncestor(root->right, p, q);
return lowestCommonAncestor(root->left, p, q);
}